Well, I guess the manual was rather short. But I will improve it over time, so hopefully it gets better.
Anyway I will try to explain:
- The MMU either act on a 4KB memory block (4K-mode) of your choice or on the full 64KB block (64K-mode). This can be changed by the MMS instruction by setting or clearing the flag "FULL_BLOCK_MOVE". If you change this several times in a program, be careful as the program counter (PC) is affected by the JBANK register (it changes the 4 MSB of the 20-bit address bus in the current implementation).
- The Zero page can be moved around with the ZBANK register. In 4K-mode, the ZBANK affects bits 20-12 and in 64K-mode the ZBANK affects bits 20-16. Every memory block (4KB blocks in 4K-mode or 64KB blocks in 64K-mode) can have a Zero page that is located in another memory block. If you don't touch the ZBANK register, all Zero page accesses will be into $0000-$00ff (as normal 65C02 operation). Note that stack location also changes with ZBANK, but always starts at Zero Page location+$100. Thus you have to be careful when moving Zero Page location around as it can affect the next RTS. A safe way is to set all Zero page locations before you start using the stacks.
- In 4KB mode, 60KB of the 0-64KB adressable range of the 65C02 is not affected by the MMU. E.g. it operates "normally" as without a MMU. The rest (4KB) that is affected by the MMU can be located in any 4KB block in the 0-64KB adressable range. The location of this 4KB block is decided by the BLOCK register. If for example BLOCK register=$A, the 4KB block that starts at $A000 is going to be the MMU memory range ($A000-$AFFF). Any code or access by the 65C02 into this memory range will be controlled by the MMU. The rest of the memory is not controlled by the MMU, but can be affected by it anyway.
As you may understand this gives some interesting possibilities. For example, if we go into 4K-mode, set the BLOCK register to $A and jump into the $A000-$AFFF memory range with MMJ set to $00 (=JBANK set to $00), the MMU will allocate memory area $000-$FFF as the $A000-$AFFF. It means that the Zero page of non-MMU memory will also start from $A000 (I know, kind of confusing). If you now set ZBANK register (which always sets ZBANK of the current JBANK to (for example) $1, the Zeropage of the current MMU block will be allocated to $1000 (even more confusing). The thing is that if code in the $A000-$AFFF area is now running and accessing Zero Page, the bytes will appear at $1000-$10FF (which by coincidence is also visible in non-MMU memory area).
I will try to make some drawings to better visualize this as it can be very confusing, but it all makes sense once you understand it. E.g. in 4K-mode, the whole memory is divided into 4KB blocks and whatever block you see will appear in the $A000-$AFFF area (in the above example) according to what the MMJ or MMF instructions sets as the block number. Each block can have its zero page located in another block, which gives versatility.
4K-mode address:
Code:
<----bits decided by MMU---><--bits decided by 65C02-->
[20 19 18 17 16 15 14 13 12][11 10 9 8 7 6 5 4 3 2 1 0]
The bits decided by MMU is set using MMJ (for JMP or JSR, e.g. PC location) or MMF for reading or storing (LDA/X/Y,STA/X/Y,INC,PHP,TSX and so on...). MMJ sets the JBANK register and MMF the FBANK register. In 4K-mode, bits 20-12 of the PC are equal to the current JBANK register.
For example program starts at $1000 in non-MMU mode:
Code:
$1000 MMS %10101010 Set MMU to standby
$1002 MMS %01010101 Start MMU
$1004 MMS %01000000 Set MMU flags: BANK_REG_MEM=OFF, IGNORE_LSB=OFF, IBANK MODE/MMJ STORE=OFF, SWAP=0, FULL_BLOCK_MOVE=OFF (4K-mode), PROTECTED_MEMORY=OFF
$1006 MMB #$f Set BLOCK register to $f ($f000-$ffff is MMU memory)
$1008 MMF $0010 Set MMU memory block to start at $0010000
At this point, any access to $f000-$ffff by the 65C02 will either read or store bytes in the $0010000-$0010fff memory area (or $10000-$10fff if you trunkate it to 20 bits). So we can do that with ease:
Code:
$100B LDA #$D0 Load the value $D0 into accumulator
$100D STA $f001 Store the accumulator value into $10001
So in practice, the MMU does banking but in a more transparent way. If you copy some code to $10000, you can then jump to this code using JMP or JSR with a preceding MMJ:
Code:
$100B MMJ $0010
$100E JMP $f000 Jump to $10000
As you are probably thinking; how does this work with JSR and RTS? Well, there is a JBANK stack that stores current JBANK value so that any RTS will return to the previous JBANK. Just as the normal 65C02 stack, but stored in another location. The JBANK stack can be exposed by setting the BANK_REG_MEM to ON (it will then be exposed at $0100-$01ff until BANK_REG_MEM is set to OFF).
For 64K-mode, the whole adressable 65C02 range is banked (and shifted with the different BANK registers). Thus there is no non-MMU memory in 64K-mode, and the whole memory is divided into 64KB blocks (instead of 4KB blocks as above). Zero page location will always start at $0000 in the current memory block, but can be located at other memory blocks using the ZBANK register. E.g. several 64KB program blocks can share the same Zero page.