Best way to implement CHR/PRG Bank switching?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Best way to implement CHR/PRG Bank switching?
by on (#65295)
Hello all!

I've been working on my emulator, and am about to start adding memory mappers. So I've been trying to think of the best way to create a somewhat generic set of methods to accomplish CHR/PRG bank switching. Admittedly, I am something of a novice when it comes to bank switching, so go easy on me! :P

Something like the following will be used in my mapper base class:

Code:
public:
  virtual void SwitchChr() = 0;
  virtual void SwitchPrg() = 0;


Now, the parts I'm unsure of are the following:
1. What parameters will be needed for those methods. (I know I need to specify what size bank I am attempting to switch, but other than that..)
2. If I should have some sort of method that will allow you to modify the values passed to the mapper by the currently running game. (I don't want to do this in the calls to the Switch methods, and have ugly looking code!)

It would be ideal in my opinion to have some sort of pointer array, to keep track of which bank is holding which page of PRG/CHR rom:

Code:
BYTE* prgBank[8];
BYTE* chrBank[8];


But I am unsure, so I'm asking; What do you guys think is the best way to implement what I want?

If I have been unclear, let me know and I will try to correct that!

by on (#65296)
I believe most people break up the memory into chunks of the smallest bank sizes known to be used by mappers (that would be 4KB for PRG and 1KB for CHR). Then if larger banks than that are used, you just have to adjust multiple pointers (i.e. if the mapper uses 16KB PRG chunks you have to modify 4 pointers to point to 4 contiguous 4KB segments).

I believe your switch methods need 3 parameters: the memory that will become visible (which part of the entire chip), where it will be visible in the NES addressing space (so that you know which pointers to change) and the bank size (so that you know how many pointers to change). All parameters depend on the mapper being used and the values written to its registers.

by on (#65297)
tokumaru wrote:
I believe most people break up the memory into chunks of the smallest bank sizes known to be used by mappers (that would be 4KB for PRG and 1KB for CHR). Then if larger banks than that are used, you just have to adjust multiple pointers (i.e. if the mapper uses 16KB PRG chunks you have to modify 4 pointers to point to 4 contiguous 4KB segments).

I believe your switch methods need 3 parameters: the memory that will become visible (which part of the entire chip), where it will be visible in the NES addressing space (so that you know which pointers to change) and the bank size (so that you know how many pointers to change). All parameters depend on the mapper being used and the values written to its registers.


That's the biggest part I want to address here. I've looked around at some other emulators, to see how they handle this. Some have method calls like this:


Code:
Switch16kPrg((data & ((PRGPages << 2) - 1), 0);


The above code is an eyesore to me, and there has to be a better way.. So that I only have to do something like the following

Code:
Switch16kPrg(data, 0);


Maybe with an internal way of modifying the values passed in, that can be set for each mapper, etc. Do you see what I mean?