Discussion:
How does IIgs register $C035 bit 6 affect $e000+?
(too old to reply)
Thomas Harte
2020-10-20 17:08:29 UTC
Permalink
To quote the IIgs Hardware Reference:

"The I/O and language-card (IOLC) inhibit bit: This bit controls whether the 4k range from $C000 to $CFFF in banks $00 and $01 acts as RAM or I/O. When this bit is 0, I/O is enabled in the $Cxxx space and the RAM that would normally occupy this space becomes a second $dxxx RAM space in banks $00 and $01, forming a language card.
...
When this bit is 1, the I/O space and language card are inhibited and contiguous RAM is available from $0000 through $FFFF."

So that doesn't specify what happens to $e000–$ffff when that bit is 0. Though I note in the Firmware Guide, when discussing interrupts:

"If I/O shadowing is on, then the system ROM in bank $FF is shadowed and readable in bank $00"

Is it safe to assume that if IOLC is not inhibited then the end of the system ROM is shadowed into bank $00 to appear with the normal 8-bit placement? Or is there some other control bit that I need to hunt down?
Kent Dickey
2020-10-20 19:27:19 UTC
Permalink
Post by Thomas Harte
"The I/O and language-card (IOLC) inhibit bit: This bit controls whether
the 4k range from $C000 to $CFFF in banks $00 and $01 acts as RAM or
I/O. When this bit is 0, I/O is enabled in the $Cxxx space and the RAM
that would normally occupy this space becomes a second $dxxx RAM space
in banks $00 and $01, forming a language card.
...
When this bit is 1, the I/O space and language card are inhibited and
contiguous RAM is available from $0000 through $FFFF."
So that doesn't specify what happens to $e000–$ffff when that bit is
"If I/O shadowing is on, then the system ROM in bank $FF is shadowed and
readable in bank $00"
Is it safe to assume that if IOLC is not inhibited then the end of the
system ROM is shadowed into bank $00 to appear with the normal 8-bit
placement? Or is there some other control bit that I need to hunt down?
When $C035 bit 6 is 0, memory from $c000-$ffff in banks 0 and 1 work like
an Apple //e, with all the language card, ROM, and IO space soft switches
(built-in and peripherals) behaving as you would expect on a //e affecting
accessing to banks 0 and 1.

When $C035 bit 6 is 1, memory from $c000-$ffff in bank 0 is the DRAM from
$c000-$ffff--there is no LC bank switching, no ROM, and no IO space soft
switches. And similarly in bank 1 (but it points to bank 1 DRAM).

During normal IIgs operation (running any regular OS, such as GSOS/ProDOS 16,
or ProDOS 8), $C035 bit 6 will always be 0. Only specialized demos seem
to mess with $C035 bit 6. You can assume that unless you're the one
setting it, $C035 bit 6 will be 0.

This setting ($C035 bit 6 set to 1) is the only way to get non-ROM vectors
for breaks/IRQs. The IIgs will always use ROM (regardless of LC setting)
to get the $FFFE or $FFE6/$FFEE vector, unless this is set. This differs
from a //e or other II where the active LC RAM at $FFxx will be used if the
LC is active.

Standard Apple //e memory mapping is complex, and I think that is your
actual question. What is it you're trying to do?

Kent
Thomas Harte
2020-10-20 19:59:35 UTC
Permalink
Post by Kent Dickey
When $C035 bit 6 is 0, memory from $c000-$ffff in banks 0 and 1 work like
an Apple //e, with all the language card, ROM, and IO space soft switches
(built-in and peripherals) behaving as you would expect on a //e affecting
accessing to banks 0 and 1.
When $C035 bit 6 is 1, memory from $c000-$ffff in bank 0 is the DRAM from
$c000-$ffff--there is no LC bank switching, no ROM, and no IO space soft
switches. And similarly in bank 1 (but it points to bank 1 DRAM).
During normal IIgs operation (running any regular OS, such as GSOS/ProDOS 16,
or ProDOS 8), $C035 bit 6 will always be 0. Only specialized demos seem
to mess with $C035 bit 6. You can assume that unless you're the one
setting it, $C035 bit 6 will be 0.
This setting ($C035 bit 6 set to 1) is the only way to get non-ROM vectors
for breaks/IRQs. The IIgs will always use ROM (regardless of LC setting)
to get the $FFFE or $FFE6/$FFEE vector, unless this is set. This differs
from a //e or other II where the active LC RAM at $FFxx will be used if the
LC is active.
Standard Apple //e memory mapping is complex, and I think that is your
actual question. What is it you're trying to do?
Just research; writing emulators is one of my hobbies and reading up as though I were going to write one even more so. But this feels like a day one-type question — the documentation didn't feel particularly explicit as to how the reset vector ends up being sourced from ROM and therefore how the system even starts up.

As well as the Hardware Reference and the Firmware Guide, I also checked the Fischer book; I'm grateful for your answer indicating that bit 6 does affect the entire range from $c000 to the end of each bank, which both explains how appropriate vectors are visible straight from the power-on reset and how they can point to useful code.

I think I'm actually fine with //e mapping; I wrote https://github.com/TomHarte/CLK/wiki/Apple-IIe-Memory-Paging to summarise it for myself back when I wrote an emulator of that. I hope it's accurate (and, indeed, comprehensible). So if I've fully understood then I guess the main difference on a IIgs with bit 6 = 0 versus a IIe is that VPB also factors in? I can't imagine that they changed the rules for regular memory accesses.

I'm also taking it from the documentation and your commentary that with bit 6 = 0, banks $00 and $01 have exactly the same contents. Presumably that's a safeguard against those addressing modes, like abs, x, that can now cross bank boundaries?
Kent Dickey
2020-10-21 19:52:31 UTC
Permalink
Post by Thomas Harte
Post by Kent Dickey
When $C035 bit 6 is 0, memory from $c000-$ffff in banks 0 and 1 work like
an Apple //e, with all the language card, ROM, and IO space soft switches
(built-in and peripherals) behaving as you would expect on a //e affecting
accessing to banks 0 and 1.
When $C035 bit 6 is 1, memory from $c000-$ffff in bank 0 is the DRAM from
$c000-$ffff--there is no LC bank switching, no ROM, and no IO space soft
switches. And similarly in bank 1 (but it points to bank 1 DRAM).
[snip]
Post by Thomas Harte
Post by Kent Dickey
Standard Apple //e memory mapping is complex, and I think that is your
actual question. What is it you're trying to do?
Just research; writing emulators is one of my hobbies and reading up as
though I were going to write one even more so. But this feels like a day
one-type question — the documentation didn't feel particularly
explicit as to how the reset vector ends up being sourced from ROM and
therefore how the system even starts up.
The IIgs documentation is not as complete as the previous generation.
That's partly because they basically don't document things that don't
affect people writing normal software. I'm not sure where the vector
pull always coming from ROM is documented.
Post by Thomas Harte
As well as the Hardware Reference and the Firmware Guide, I also checked
the Fischer book; I'm grateful for your answer indicating that bit 6
does affect the entire range from $c000 to the end of each bank, which
both explains how appropriate vectors are visible straight from the
power-on reset and how they can point to useful code.
https://github.com/TomHarte/CLK/wiki/Apple-IIe-Memory-Paging to
summarise it for myself back when I wrote an emulator of that. I hope
it's accurate (and, indeed, comprehensible). So if I've fully understood
then I guess the main difference on a IIgs with bit 6 = 0 versus a IIe
is that VPB also factors in? I can't imagine that they changed the rules
for regular memory accesses.
There are other differences around shadowing. The actual video buffers
are not in banks $00 or $01, but rather in $e0 and $e1, and writes to
banks $00 and $01 are shadowed to also be done to banks $e0 and $e1.
Note that the shadowing is done at the true bank level--so if RAMWRT is
set so that writes to address $1000 really go to bank 1, then those writes
are shadowed to bank $e1.
Post by Thomas Harte
I'm also taking it from the documentation and your commentary that with
bit 6 = 0, banks $00 and $01 have exactly the same contents. Presumably
that's a safeguard against those addressing modes, like abs, x, that can
now cross bank boundaries?
Banks $00 and $01 combine to make 128KB of memory that look like an Apple
//e's 128KB of memory (except these are not the actual video buffers). The
way to think of it is generating accesses to bank $00 addresses may actually
reference bank $00 or bank $01, and may shadow writes to bank $e0 (or $e1),
depending on the //e softswitches. But, directly access bank $01 using the
65816 long addressing modes will always access bank $01 (although again,
writes can be shadowed to bank $e1). Accessing other banks just accesses the
indicated bank, and there's no shadowing.

Banks $e0 and $e1 have the actual video memory (main and aux), which you can
directly access if you want. This memory is all running at 1MHz. It's not
that useful, so the ROM uses most of bank $e0 and $e1 that are not video
memory as storage for things like the Memory Manager, etc.

All of my knowledge about IIgs addressing is in my emulator, KEGS,
at http://kegs.sourceforge.net/ (Old version from 15 years ago), with an
alpha update at: https://sourceforge.net/projects/kegs/ which is cleaned up
a bit. KEGS 1.00+ is intended for Mac OS X and Linux. The memory mapping is
handled in moremem.c. KEGS has a table of 65536 remap entries for
every page of $100 bytes (so it covers the entire 16MB of addressing), so
KEGS just has to fiddle with these pointers when the softswitches are
touched. moremem.c has "fixup" routines which handle each softswitch.
Actual emulation is basically a lookup of this pointer, then add the offset
onto the page, and then access that location.

I will look into your emulator, I'm interested in using Metal on Mac OS X
in KEGS. I'm pretty disappointed in the Mac programming documentation.

Kent
Thomas Harte
2020-10-22 19:01:40 UTC
Permalink
Post by Kent Dickey
Banks $00 and $01 combine to make 128KB of memory that look like an Apple
//e's 128KB of memory (except these are not the actual video buffers). The
way to think of it is generating accesses to bank $00 addresses may actually
reference bank $00 or bank $01, and may shadow writes to bank $e0 (or $e1),
depending on the //e softswitches. But, directly access bank $01 using the
65816 long addressing modes will always access bank $01 (although again,
writes can be shadowed to bank $e1). Accessing other banks just accesses the
indicated bank, and there's no shadowing.
Thanks for the additional information; I can see now that part of my problem has been conflating the language card and auxiliary memory, and another was making a false assumption about what would be strictly logically behind the Mega II. I think I have a much better handle on it now, thanks to you.

I may still be way off, of course, but it looks like the language card switches affect the top of all four banks (being shown on Page 34 and 42 for banks $00 and $01, and Page 46 for banks $e0 and $e1), and the auxiliary switches as you say merely permit some substitution of bank $01 into bank $00. And then shadowing optionally adds a synchronise-and-write-through step to any writes.
Post by Kent Dickey
All of my knowledge about IIgs addressing is in my emulator, KEGS,
at http://kegs.sourceforge.net/ (Old version from 15 years ago), with an
alpha update at: https://sourceforge.net/projects/kegs/ which is cleaned up
a bit. KEGS 1.00+ is intended for Mac OS X and Linux. The memory mapping is
handled in moremem.c. KEGS has a table of 65536 remap entries for
every page of $100 bytes (so it covers the entire 16MB of addressing), so
KEGS just has to fiddle with these pointers when the softswitches are
touched. moremem.c has "fixup" routines which handle each softswitch.
Actual emulation is basically a lookup of this pointer, then add the offset
onto the page, and then access that location.
Cool, I somehow failed to spot that I was talking to royalty! I generally avoid looking at the source code of other emulators for a bunch of pragmatic reasons — primarily that the emulation problem is solved at this point, so it's no disaster if I can't figure something out — and at least one ethical (and technically legal): mine is MIT licensed so there's a delicate line at play if I read GPL code.

That said, you may not be surprised to learn that I did essentially the same thing for the 8-bit Apple IIs, albeit with only the 256 pairs of pointers necessary and, of course, no need to flag potential shadowing. In the abstract I'm actually perfectly happy to include switch and if chains in my cycle-by-cycle address decoding if they're neater, because modern computers are very fast and my time is finite, but when I made the step up to the IIe that was no longer the case.
Post by Kent Dickey
I will look into your emulator, I'm interested in using Metal on Mac OS X
in KEGS. I'm pretty disappointed in the Mac programming documentation.
Yeah, I tend to think that Apple's documentation in general was really good about a decade ago but nowadays it's a bit of a disaster. My emulator is a little atypical in terms of what it pushes to the GPU — it's always linear one-dimensional diagonal scans, an internal PLL having been fed a one-dimensional video signal and extracted them, and for the Apple II the pixel format is monochrome with any NTSC decoding done in a generic fashion over on the GPU.

But even with those things being the case, the addition of Metal was only about a month of hobby-time work as it fits very neatly with the rest of the OS — it's just a serial queue and the shading language is very close to C++11. There are still some rough edges in my implementation but I'm happy enough with it to file those mentally into the backlog. It also has quite a few performance advantages over Apple's almost-decade-old version of OpenGL, most obviously because you can be overt about where buffers live and when/whether they actually need to go into the GPU cache. E.g. my Mac has only embedded graphics but for this sort of program where all content is streamed that's an advantage as you can just put your intermediate pixel buffers in shared memory.

If there's anything I can do to help, let me know.

Thomas Harte
2020-10-21 20:06:49 UTC
Permalink
Post by Thomas Harte
Just research; writing emulators is one of my hobbies and reading up as though I were going to write one even more so. But this feels like a day one-type question — the documentation didn't feel particularly explicit as to how the reset vector ends up being sourced from ROM and therefore how the system even starts up.
As well as the Hardware Reference and the Firmware Guide, I also checked the Fischer book; I'm grateful for your answer indicating that bit 6 does affect the entire range from $c000 to the end of each bank, which both explains how appropriate vectors are visible straight from the power-on reset and how they can point to useful code.
I think I'm actually fine with //e mapping; I wrote https://github.com/TomHarte/CLK/wiki/Apple-IIe-Memory-Paging to summarise it for myself back when I wrote an emulator of that. I hope it's accurate (and, indeed, comprehensible). So if I've fully understood then I guess the main difference on a IIgs with bit 6 = 0 versus a IIe is that VPB also factors in? I can't imagine that they changed the rules for regular memory accesses.
I'm also taking it from the documentation and your commentary that with bit 6 = 0, banks $00 and $01 have exactly the same contents. Presumably that's a safeguard against those addressing modes, like abs, x, that can now cross bank boundaries?
Actually, I withdraw the questions above having already improved my understanding of how shadowing and banking are distinct, as is much of the $00/$01 and $e0/$e1 banking state, so a 256kb machine isn't in practice just a 128kb machine with an additional 128kb write-through cache.

Anyway, clearly I've still yet to get a full handle on things and the members of this group don't need to be bothered by my slow and annunciated comprehension. So thanks again for helping me with the first question, I think it's helped a lot to break my initial mental ice.
Loading...