Hi, my emulator is currently only supporting mapper 0, so the PRG-ROM is just a 32 kB chunk that gets loaded at ROM load and that's it.
So mappers that switch entire 32 kB PRG banks are trivial, but for mapper 2-UNROM, for example, that uses one switchable 16 kB bank and another one fixed, I've thought of these options:
1) Just switch the switchable bank, using a pointer to the selected bank, in which case I have to modify my CPU code because if the PC crosses the bank boundary, I'll have to point to a different chunk in memory, cause they won't be next to each other.
2) I could instead of switching pointers just copy over the whole switchable bank on each bank switch so both banks are always next to each other in memory and PC movement is transparent. It looks unefficient, but moving 16 kB in a modern computer should be near cost zero.
3) I also could create whole 32 kB chunks in memory, one for each switchable 16 kB bank, all with copies of the fixed 16 kB bank so I could just switch between them transparently.
Any ideas? a better solution?
My emulator is made in C.
Advices on implementing mixed switchable and fixed PRG banks
Moderator: Moderators
Re: Advices on implementing mixed switchable and fixed PRG b
FCEUX uses an array of function pointers and calls the correct one for each memory access.
Using memcpy will produce subtle bugs later on, e.g. when you get to MMC5.
Using memcpy will produce subtle bugs later on, e.g. when you get to MMC5.
Re: Advices on implementing mixed switchable and fixed PRG b
Imo, the simplest option (in the long run), is #1 - an array of pointers (e.g what lidnariq suggested)
When you consider the mappers with bank-switchable PRG RAM at $6000-$7FFF, it becomes hard to ensure your copy and the original stay in sync - it's simpler to just keep a single copy of the data.
Also, keep in mind that PRG ROM can be technically mapped outside the $8000-$FFFF range (although I forget if any mapper actually does this) and that banks can be smaller than 16kb (I believe 8kb is the smallest I have seen for PRG ROM, but smaller banks exist when it comes to PRG RAM)
When you consider the mappers with bank-switchable PRG RAM at $6000-$7FFF, it becomes hard to ensure your copy and the original stay in sync - it's simpler to just keep a single copy of the data.
Also, keep in mind that PRG ROM can be technically mapped outside the $8000-$FFFF range (although I forget if any mapper actually does this) and that banks can be smaller than 16kb (I believe 8kb is the smallest I have seen for PRG ROM, but smaller banks exist when it comes to PRG RAM)
Re: Advices on implementing mixed switchable and fixed PRG b
FME-7 can bank ROM instead of RAM to $6000. JY Company's mapper collection can too. A bunch of the pirate FDS ports have unbankable ROM fixed there (m40, m50).Sour wrote:Also, keep in mind that PRG ROM can be technically mapped outside the $8000-$FFFF range (although I forget if any mapper actually does this)
There's something weird going on with this board where banking granularity is 4K but that's split into a 3K and a 1K nonadjacent region. Of course, it's another pirate FDS port.and that banks can be smaller than 16kb (I believe 8kb is the smallest I have seen for PRG ROM, but smaller banks exist when it comes to PRG RAM)
Re: Advices on implementing mixed switchable and fixed PRG b
I won't pretend to know how fast modern computers are at moving data, but don't fail to consider that games might switch banks dozens of times in a single frame, so you may end up with slight performance variations depending on the game/mapper.Petruza wrote:2) I could instead of switching pointers just copy over the whole switchable bank on each bank switch so both banks are always next to each other in memory and PC movement is transparent. It looks unefficient, but moving 16 kB in a modern computer should be near cost zero.
Re: Advices on implementing mixed switchable and fixed PRG b
It sounds like you've got assumptions about the NES memory layout hardcoded into your CPU implementation. This isn't a good idea and will only further break down as you attempt to emulate more sophisticated mappers (ones with multiple bank slots like MMC3, ones with registers below address $8000 like many third-party mappers, ones which can map RAM above address $8000 and/or map ROM below it like Sunsoft mappers and MMC5) You need to implement an abstract memory system; take a look at FCEU for an example (it's C++ but the actual emulation components were originally written in C and AFAIK are still entirely C-like code that doesn't make use of classes or polymorphism or other C++ features)Petruza wrote:Hi, my emulator is currently only supporting mapper 0, so the PRG-ROM is just a 32 kB chunk that gets loaded at ROM load and that's it.
So mappers that switch entire 32 kB PRG banks are trivial, but for mapper 2-UNROM, for example, that uses one switchable 16 kB bank and another one fixed, I've thought of these options:
1) Just switch the switchable bank, using a pointer to the selected bank, in which case I have to modify my CPU code because if the PC crosses the bank boundary, I'll have to point to a different chunk in memory, cause they won't be next to each other.
2) I could instead of switching pointers just copy over the whole switchable bank on each bank switch so both banks are always next to each other in memory and PC movement is transparent. It looks unefficient, but moving 16 kB in a modern computer should be near cost zero.
3) I also could create whole 32 kB chunks in memory, one for each switchable 16 kB bank, all with copies of the fixed 16 kB bank so I could just switch between them transparently.
Any ideas? a better solution?
My emulator is made in C.
Re: Advices on implementing mixed switchable and fixed PRG b
lidnariq wrote:FCEUX uses an array of function pointers and calls the correct one for each memory access.
Using memcpy will produce subtle bugs later on, e.g. when you get to MMC5.
Oh right! my emulator actually does have the function table for memory I/O, I haven't touched the code for almost a year now and had forgotten about that.Sour wrote:Imo, the simplest option (in the long run), is #1 - an array of pointers (e.g what lidnariq suggested) [...]
So I guess that's the most elegant solution and more well suited for future mappers too. Thanks!
Yeah, you're right.tokumaru wrote:I won't pretend to know how fast modern computers are at moving data, but don't fail to consider that games might switch banks dozens of times in a single frame, so you may end up with slight performance variations depending on the game/mapper.
You're right, but I failed to mention that my immediate next step is to implement mappers 2,3,7 & 11, which I considered a good compromise between amount of games supported and ease of implementation. Then I'll have to implement more important things before moving to implement MMCs and other mappers. (The whole APU is missing, lightgun support, state save, save RAM, etc.)AWJ wrote:It sounds like you've got assumptions about the NES memory layout hardcoded into your CPU implementation. This isn't a good idea and will only further break down as you attempt to emulate more sophisticated mappers (ones with multiple bank slots like MMC3, ones with registers below address $8000 like many third-party mappers, ones which can map RAM above address $8000 and/or map ROM below it like Sunsoft mappers and MMC5) You need to implement an abstract memory system; take a look at FCEU for an example (it's C++ but the actual emulation components were originally written in C and AFAIK are still entirely C-like code that doesn't make use of classes or polymorphism or other C++ features)
So a sub-optimal hacked solution that works with these 4 mappers would be ok for now, I can then improve it when moving to other mappers but that will happen in a distant future.
Never the less, I think the function table solution will be the best choice to cope with future mappers as well.
I will take another look at FCEU though.