It was recently discovered that the behaviour of MMC5 CHR ROM banking described in publically-available documents, and implemented in almost all NES emulators including FCEUX, is wrong:
NESdev forum thread
NESdev wiki
Summary of correct behaviour:
When 8x8 sprites are used, the registers from $5120-5127 ("set A") are used for everything (sprites, BG tiles, and reads from $2007 during vblank or forced blank). Registers $5128-512B ("set B") are unused.
When 8x16 sprites are used, sprites use the "set A" banks; BG tiles use the "set B" banks; reads from $2007 during vblank or forced blank are treated as sprite accesses (using bank set A) if the most recently written register was $5120-5127; and treated as BG accesses (using bank set B) if the most recently written register was $5128-512B.
The .nes file in the attachment can be used to test the MMC5 CHR banking behavior with various settings of PPU and MMC5 registers (it's the same as the one attached in the NESdev forum thread)
Commercial games to regression test:
Uchuu Keibitai SDF title screen (the nametable is stored in CHR ROM and copied to VRAM during forced blank)
Bandit Kings of Ancient China, start a new game, select scenario 2, 3 or 4, pick your character and get ingame, and see that your character's stats, initial location, etc., are all right (the initial game state for scenarios other than scenario 1 is stored in CHR ROM and slowly copied to cartridge SRAM over many vblanks while "please wait..." is displayed onscreen)
Please check https://github.com/TASVideos/BizHawk/commit/d8fd403ea238f70a822d8048cf4c256921daaca9 and see if that is a correct change from "publically available documents" (is nesdevwiki up to date yet?) to your new description written here
I have no way of compiling C# here, but that looks correct. The description on nesdevwiki is up to date.
See if r3351 works for you (note: may only work in newppu, i didnt test)
I dont understand it enough to know what to do with your test, I'll let you check it. I checked the two regression cases
Sorry, can you provide a binary? I'm on Linux, I can run Windows FCEUX via Wine but I can't build it.
This might not affect the test results, but the fact that that code is individually checking "BG enabled" and "sprites enabled" in the PPU (register $2001) looks wrong to me. On a real NES, if you disable just the sprites or just the BG, the PPU still fetches both the sprites and the BG, it just doesn't mix the disabled layer into the video output. The MMC5 (and anything else that's concerned by PPU bus activity) should only care whether the PPU is in forced blank ($2001 & 0x18 == 0) or not.
Fixed in r3352.
If the PPU is disabled (is that the same as "forced blank"?) then the CHR side of the chip shouldn't even know what's going on. Are you sure, in this case, it isn't being glitched out somehow by the pattern of reads, rather than depending on the last written register? It seems to me we should be attempting to emulate the logic that determines what stage of display it is, instead of "knowing" what the PPU is up to, and using that to drive the banking logic. Then again, maybe the MMC5 watches the pattern of reads from cpu vs ppu and specially decides the PPU is halted when the CPU runs without the PPU.
builds for emu folk paddling upstrea:m https://ci.appveyor.com/project/zeromus/fceux/build/artifacts
The "latest build" is 2 months old...
fixed
Okay, CHR banking now conforms to hardware with the new PPU. but is the same as before with the old PPU.
On the other hand, extended attributes don't work properly with the new PPU yet. The tile banks are correct, but it looks like the attributes (colors) are still coming from the regular attribute tables. This can easily be seen in e.g. the Nobunaga's Ambition II title screen (compare the colors with old PPU vs new PPU)
The attached screenshots show what the correct output of the mmc5test.nes program should be. The first four screenshots are taken with the new PPU and the last two with the old PPU. There are no screenshots for 8x8 sprites + extended attributes because neither PPU currently gets it right (old has the banks wrong, new has the screen colors wrong). It should be the same OBJ and DATA banks as without extended attributes, BG banks CDEF, and all the letters in rainbow colors.
If you run the test program, follow the onscreen instructions to change the the sprite size, the EXRAM mode and the bank setting order. Don't worry about combinations other than the ones shown in the screenshots, like the ones where the banks are written in scrambled order. If you can get the combinations shown in the snaps correct then everything else should be correct as well.
Last edit: Alex W. Jackson 2017-04-29
extended attributes for newppu fixed in r3360
The first four screenshots are all correct? Then there's nothing more that needs to be done for new PPU.
Now, the oldppu needs the new banking logic.
I fixed that in r3360 too.
Is it all fixed now?
The old PPU is still using the B banks when reading $2007 during vblank with 8x8 sprites. See the attached screenshot and compare with the correct one in the previous attachment
For extended attributes, you don't have to calculate what bit position to put the attribute bits in; you can just duplicate them over the entire byte like this:
(byte >> 6) * 0x55That's most likely what the real chip does.fixed in r3361
Everything looks good now and this bug can be closed.
It'd be nice for debugging MMC5 games if there was a way to switch the PPU viewer between showing the sprite banks and the BG banks when they are different. But consider that a low-priority feature request (the MMC5 games I'm interested in debugging at the moment all use extended attributes anyway)
Yeah, by "forced blank" I mean $2001 & 0x18 = 0.
In order to implement different CHR banks for sprites and BG, extended attributes (bank and palette per 8x8 tile), and vertical splits, the MMC5 has to contain some kind of state machine that closely tracks what the PPU is currently doing (i.e. whether it's fetching sprites or BG, and in the latter case what screen column it's currently on).
There's a lot of discussion in this thread
Short version: there's conclusive evidence that the MMC5 synchs with the PPU by recognizing a particular access pattern that happens around the start of each scanline: the PPU redundantly reads the same VRAM address 3 times in a row. This is how MMC5 clocks its IRQ counter and also how it starts counting columns to know when to trigger the vertical split and when to switch between BG banks and sprite banks. The MMC5 can also detect the end of rendering, probably by noticing when the PPU bus has gone idle for more than x clocks. So yes, the MMC5 always knows when the PPU is rendering and when it isn't, and it can even share that information with the CPU via $5204 bit 6.
This is why MMC5 cartridges don't work in famiclones, by the way: the clone hardware doesn't have exactly the same bus access patterns as an original Nintendo PPU, so the MMC5 can't synch with it. So neither extended attributes nor IRQs work, and every MMC5 game uses at least one of them.
Implementing all this shit in an emulator without cheating (giving the emulated PPU and MMC5 access to each other's states) is extremely difficult, I'm not sure any emulator does it, and doing it in a 15-year-old codebase like FCEUX is probably a fools errand.
Oh, and nobody is sure how the MMC5 detects whether sprites are 8x8 or 8x16, but my test program running on an original cartridge proves that somehow it does. The best guess is that it spies on writes to $2000.
OK, thanks for filling me in. I'm extra-sure now I don't want to be an expert on anything except wrestling with fceux to solve within dotted lines you drew. Let me know if you discover any more problems.