Mappers

Discuss emulation of the Nintendo Entertainment System and Famicom.
rhughes
Posts: 12
Joined: Mon May 21, 2012 3:39 am

Post by rhughes »

So is it one board type per mapper, or can one board have multiple mapper types? I know there are some sub types like A1, B1 etc...
tepples
Posts: 23006
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)

Post by tepples »

TLSROM is always 118. TQROM is always 119. Any other T*ROM is 4. Most of the various S*ROM and T*ROM are for different sizes of PRG and CHR ROM, which need different pinouts, but for the most part, they behave identically.

There are only a couple boards that can be wired up for more than one mapper. One of them is UNROM, which is most commonly mapper 2, or mapper 180 if one logic chip is replaced (which one commercial game and one homebrew multicart use). Another is CNROM, which can be wired up as a CHR ROM switch (mapper 3) or as extra enables to perform weak copy protection (mapper 185).

Some boards have revision numbers, such as NES-CNROM-02 vs. NES-CNROM-05. These do not affect behavior but instead generally improve some aspect of the board's electrical reliability.

Some mapper chips have revisions that do affect behavior. The biggest examples I can think of are MMC1, whose PRG RAM enable (controlling access to 8 KiB of SRAM at $6000-$7FFF) behavior changed over the three revisions, and MMC3, whose IRQ behaves differently at the lowest period value on "old" and "new" chips. The newer NES 2.0 format allows mappers to have subtype codes to distinguish e.g. MMC1 and MMC3 revisions, but nobody has defined a registry of those subtypes.

The boards assigned to a particular mapper number may have different amounts of RAM on them. For example, mapper 1 (MMC1) can have no PRG RAM (common), 8 KiB of PRG RAM (also common), two 8 KiB chips (mostly in Koei sims), or one 32 KiB chip (rare, Japan only). Mapper 5 (MMC5) has the same options. How much RAM to emulate can be determined implicitly, by the hash of the PRG ROM, or explicitly, using the NES 2.0 format.

For historical reasons, sometimes two mappers are given the same number. BNROM and NINA-001 were both given mapper 34. You can tell them apart because BNROM will have 0 KiB of CHR ROM (it uses CHR RAM instead). A harder one is mapper 4, which covers both MMC3 (T*ROM boards) and MMC6 (HKROM board). MMC6 acts just like a late-model MMC3, but its PRG RAM enable behavior differs. Only two games were ever released with MMC6, so what most emulators do is detect them by their CRC.
beannaich
Posts: 207
Joined: Wed Mar 31, 2010 12:40 pm

Post by beannaich »

One example I can think of for iNES mappers sharing the same number and having slightly differing behavior is the "VRC" series of Konami boards. The address lines being fed into the mapper differ almost from game to game. And the only way to know which wiring configuration to use is either hash checking or using a database. And mapper 4 also applies to HKROM (MMC6) since it operates similarly to the MMC3 with added battery buffered SRAM that is inside the mapper package. MMC6 was only ever used in two games if memory serves.

iNES doesn't even come close to addressing all the different layouts/boards. NES 2.0 is better, but still lacking.
That's a good point. In NESICIDE I drop the 16KB artificial boundary of a "bank" in the file while loading the file into the emulator. Inside the emulator there's only the concept of 8KB banks for both PRG and CHR. I realize this might not work well with NSF but as yet I have not tackled NSF. I would expect this is how most emulators internally represent things...trying to keep in sync with the iNES boundary is silly once you get to the actual machine emulation.
In Nintemulator, I don't even use a set in stone bank size. All of my address decoding is done as near to identical to the hardware as possible. :) For a few reasons, first and foremost being that if a mapper can change a ROM layout with a single bit, when that bit gets updated the layout is instantly updated. I don't have to mess around with my "Switch PRG" functions whenever a write is made to a register. It also doesn't degrade performance as much as you'd think, and makes my code look nicer in my opinion!