Hey, I'm a newbie mudling through trying to write an emulator as a learning exercise and this has me a little confused. Since the NES's addressing is only 16 bits, how does it access any memory outside the first 64 KB? I understand it has to change pages (or banks if you like that term better), but how? I checked all the 6502 opcodes but couldn't find anything there. I know this probably has a really simple answer, but bare with me - I'm a newbie. Thanks in advance.
Mappers.
The cart places writable registers somewhere in the $4018-$FFFF range, and these registers control the upper address lines of the program and graphics ROMs, effectively "turning the page" so to speak. The easiest to understand are UNROM/UOROM (iNES mapper #2) and CNROM (iNES mapper #3).
If you know how binary numbers work, then you'll know how adding just one more address bit would double the possible amount.
And because the NES doesn't have enough address bits to hook up to a ROM larger than 32kB, we just add more hardware so the NES can write to a cartridge to control those extra bits.
The CPU doesn't know the difference, it'll just be running whatever bank it currently 'sees'.
So, the different mappers just define more of those "special" memory registers that, when written to, change the current page?
Yep. Theres plenty of different mappers too , each with their own "style" of "changing pages"/bankswitching.
It's real simple when you think about it. The "mappers" just control the higher address lines depending on what is stored in one of the certain addresses that it uses (each mapper having different registers (memory addresses)). Usually the registers arn't just 1 certain memory address = current page, unless it's a complex IC.
UNROM boards (NES games have board names, which correspond to their mapper + other specifications) have a chip that stores whatevers in the lowest 3 bits (D0-D2), if the address written to is $8000-$FFFF (PRG /CE = 1, this = 1 because it means it's accessing the PRG Address Bus (and it does that whenever the memory address is $8000-$FFFF). It then uses the value that stored in the chip and ORs it (using another chip) with A14 which mean if A14 = 0 then the values the other chip had (the bank number) is passed onto the PRG rom chip (and changing those values changes what the CPU "sees.") If you understand binary it becomes really simple.
In other words. you load a value into the right register/s, and depending on the mapper, it will switch the current bank that the CPU "sees" depending on what the cpu is "looking at." Each mapper is different so you'll just have to read the docs + mappers can do much more than increase the memory size, you may want to look into that too.