Here's a head-hurter...
Here's a head-hurter...
A more advanced version might let you use other mapping RAM bits (we have three left over in this case) as "segment offsets", where the contents of them is added or subtracted from CPU-supplied physical address, at least for certain areas in the address space. (Again, I get fuzzy on this part. Combine the mapping RAM output with the CPU address bus with XOR gates or something?)
You know, I was thinking about this a little more, and scratching it out on a piece of paper convinces me that you could in theory access every scrap of memory in a 512Kbyte RAM chip inside of an 8K address window by using six bits on a mapper chip, set up as follows:
Three bits -> A16 through A18. (Or address line 17 through 19, whichever is less confusing.)
Other three bits -> Combine outputs via a 7486 XOR gate with A13 - A15 on the CPU bus.
The first part is easy: Setting the high address line bits selects which of eight 64K pages the CPU is mapping to for that byte/area. (Whether it's a "byte" or an "area" depends on the resolution you're using for the mapper.) The next part is confusing, so let's use a hypothetical example based on the following: You've installed this in a PET, you want to run BASIC 4.0 leaving an 8K area open in the form of two empty 4K ROM slots, &9000 and &A000, and you want to access as much RAM as possible inside that 8K area, leaving the ROMs and lower RAM spaces alone. So let's imagine how this will work.
For normal operation in booting up the PET we'll set up the mapper so everywhere in memory, IE, the ROM images and system RAM, is either coming from physical 64K page 0 or from the hardware RAM/ROM on the PET motherboard itself. So all the memory-mapping related bits are set to output "0" (And buffer/write protect bits are set appropriately as well). We also set it up so we have 8K of R/W RAM in &9000 and &A000. But... 8K isn't enough. Okay, easy enough, we'll bank switch it with the physical page bits. We got 8K worth of RAM when we had the "direct address" line bits set 000, if we want a different 8K all we need to do is set those bits to 001, 010, etc. That gives us 64K possible. But we want MOAR!
So... first off, we switch those areas to the second bank, physical address page bits to 001, to make sure we don't trod on anything vital in the zero page. Then we start playing with the three masking bits.
In binary the addresses for the start of each of our "EMS" slots is this:
1001.0000.0000.0000
1010.0000.0000.0000
Throw away everything but the first nibble (that's all tied straight through), leaving us with:
1001
1010
The last bit is also sourced directly from the CPU bus, so we can't change it, But we can mask all the others. Remember with the XOR gate we can negate anything that's set on the top three bits of the address bus. Which means, essentially, for a given address supplied by the CPU by setting or negating top three address lines you multiply the amount of memory you can reach with that address by eight. If you can supply a 4K window you can have 32K. *AND*, remember of course, you have eight pages, meaning in total you could access 256Kbytes of RAM within the address space occupied by a single ROM chip. And of course an 8K window lets you hit the entirety of a 64K physical page... and you have eight pages, giving you a grand total of 512K.
(It might be better in practice, however, to limit the maximum "EMS" memory in this scheme is 448K, saving the zero physical page for things you don't want touched in strange ways. If the MCU were setting the mapping bits rather than the 6502 writing bytes to the mapping RAM itself you could in theory even implement "memory protection" on the MCU by having it sanity check mapping requests. Actually, even better, if the MCU were accepting remap messages from the 6502 you could phrase them in a high-level manner. IE, instead of having to have the user calculate the raw mapping bit masks needed to access all the expanded RAM you could have the MCU handle the calculations and just number the pages arbitrarily, leaving it to the PET programmer to just say "I want page X of Y mapped to window Z, thank you".)
The still confusing part to remember is that by setting the appropriate mask bits within a 64K window the &9000 page will be able to access *every other 4K window of addresses*, while the &A000 page can access the opposite set of addresses, meaning the one thing you can't do is write to a page of memory mapped to the &9000 window and then read it back from the &A000 window. They're two separate address spaces. (The &9000 page will with the appropriate masking be able to hit &1000, &3000, etc, because A12 is "stuck on", while &A000 can reach &0000, &2000, etc. If we could do an 8K linear window *on an 8K boundary* then some of the confusion goes away. The problem with the &9000+&A000 example is it essentially induces an address line flip. Which can certainly be worked around, but should be called out.) The one thing you can't do is directly copy memory from one page (either direct or masked) in memory to the same location in another page within in the same window. To do that completely without compromise you'd have to be willing to allocate a total of 16K to remap windows. Which might be doable (There's nothing to say you couldn't borrow another 8K window somewhere as long as you took the proper precautions.)
Anyway, I guess I wasn't kidding when I said "segment arithmetic". This is almost weird enough to qualify as something out of an x86 programming manual. But it's lotsa RAM with almost no hardware! ;^b
(Of course, this was "back of the napkin" thinking, so I could of gotten something wrong. My boolean algebra's a little rusty.)