Alternate MMC3 emulation?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Alternate MMC3 emulation?
by on (#21425)
- The PPU address bit rising/falling thing seems too complex. Most emulators were using CRCs to identify a certain ROM and a "best" IRQ method of counting, using PPU scanlines as reference. An hack to fix some titles such as MegaManIII was to check the sprite pattern bank 0000h or 1000h.

- Is there an alternate method for proper MMC3 emulation, or near enough? My PPU code renders using tilecaching + pixel-by-pixel, without pre-caching tiles like the NES does. Well, that's it.
Re: Alternate MMC3 emulation?
by on (#21426)
Fx3 wrote:
- The PPU address bit rising/falling thing seems too complex.


It's a simple concept -- although it does end up being difficult to impliment. (You should see my current MMC3 code... hoooo boy!)


Quote:
Is there an alternate method for proper MMC3 emulation, or near enough?


Before I implimented MMC3's IRQ counter based on A12 rises, I simply had a function which I called every scanline around cycle 260. That function would clock the IRQ counter once provided all of the following were true:

- PPU is on
- 8x8 sprites: BG uses different pattern table than sprites ($2000.3 != $2000.4)
- 8x16 sprites: BG uses left pattern table ($0xxx)


That seemed to work "good enough" for most games. I was even able to get some trickier games like Kickmaster working without CRC checks or anything.

Using this method meant that my MMC3 code was then tied to my PPU code -- something which was kind of weird (but I guess it worked). However this is avoidable.

Quote:
My PPU code renders using tilecaching + pixel-by-pixel, without pre-caching tiles like the NES does. Well, that's it.


If you want to stick with the A12 route -- how your PPU renders doesn't need to play any role in how you emulate MMC3's IRQ counter. In fact in my current emu -- the PPU and MMC3 counter operate completely independently (although my MMC3 does need to "see" certain things in the PPU). If you're interested I can explain how my current system works and perhaps draw some diagrams or something. But it'd be a pretty big explanation so I don't want to post it unless you're really interested.

by on (#21427)
It's not that complex, there are simpler ways to have the same effect. Just look for the few things that will change the PPU address.

This post says it all:
Quote:
If sprites are set to $1000-1FFF and the background is set to $0000-0FFF, then A12 will change from 0 to 1 at cycle 260 of each scanline, then change from 1 to 0 at cycle 320 of each scanline.

If sprites are set to $0000-0FFF and the background is set to $1000-1FFF, then A12 will change from 1 to 0 at cycle 256 of each scanline, then change from 0 to 1 at cycle 324 of each scanline.


And make sure to not have it increment if sprites and BG are on the same pattern table, otherwise you break Kick Master.

When sprites are 8x16, and none are displayed on the scanline, it gets sprite data from 1000-1FFF.

If 8x16 sprites take data from the left pattern table, then you advance the counter more times than it's supposed to, and it breaks the status bar in Mario Adventure.

Monitoring all writes to the PPU Address to see if any change the IRQ counter is only useful if you're trying to pass blarrg's tests. I don't think any game actually relies on this.

by on (#21430)
Quote:
Monitoring all writes to the PPU Address to see if any change the IRQ counter is only useful if you're trying to pass blarrg's tests. I don't think any game actually relies on this.
Knowing that literary hundreds of games use the MMC3, you'd want emulation to be very accurate.

by on (#21433)
hap wrote:
Quote:
Monitoring all writes to the PPU Address to see if any change the IRQ counter is only useful if you're trying to pass blarrg's tests. I don't think any game actually relies on this.

Knowing that literary hundreds of games use the MMC3, you'd want emulation to be very accurate.

Would you rather have
  1. accurate at 50 percent speed on a handheld device,
  2. hacky at 100 percent speed on a handheld device, or
  3. accurate at 50 percent speed on a large, expensive laptop?
Accurate, fast, small: choose two. That's the breaks when your target platform has only 280,896 CPU cycles to emulate 29,780.5 NES CPU cycles.

by on (#21435)
Quote:
Monitoring all writes to the PPU Address to see if any change the IRQ counter is only useful if you're trying to pass blarrg's tests.

Probably so. It's worth implementing even if just to pass my test, since without this behavior it's harder to test the scanline counter operation in an emulator-independent way.

by on (#21465)
I've implemented the toggling without the actual MMC3 yet. It's inefficient though since it requires running all ppu fetches through it.

Code:
ppu_read(address) {
address &= 0x3fff;
if (address < 0x2000) { ppu.a12 = 0; return read_chr(address); }
if (ppu.a12 == 0) a12_counter++;
ppu.a12 = 1;
//decode_other_stuff
}

by on (#21477)
A12 is $1000, not $2000

by on (#21497)
You get the point though ;)