Question about emulating UxROM mapper (mapper 002)

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
wbrian
Posts: 11
Joined: Wed Feb 15, 2017 6:41 pm

Question about emulating UxROM mapper (mapper 002)

Post by wbrian »

I have a few questions about emulating mapper 002. I've been looking at https://wiki.nesdev.com/w/index.php/UxROM as a reference.

- The documentation lists the address for the bank select register as "($8000-$FFFF)". This is confusing because it lists an address range. How should this be interpreted? I'm expecting a fixed memory location.

- Verifying an assumption: If a cart has 8 PRG-ROM banks, I assume the 3-bit bank select value can be thought of as an index to the bank mapped to $8000-$BFFF

- Specifically regarding the mega man cart, which is mapper 02: It doesn't have CHR-ROM or CHR-RAM. I verified this in FCEUX to make sure I wasn't decoding the ROM file incorrectly. Where does it read CHR data from?

As always, I appreciate any insights :)
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Question about emulating UxROM mapper (mapper 002)

Post by rainwarrior »

The register being mapped to $8000-FFFF means that writes anywhere in that range apply. It's the same register at all those addresses, it's really just responding to the write, and only has to pay attention to one bits worth of the address to see that it's in that particular range (i.e. address & $8000).

If a PRG-ROM only has 8 banks, yes only the low 3 bits apply to the bank selection. Larger or smaller roms will use more or less bits of the value being written to the register, and the high bits are ignored. (Other mappers might have other rules for this, but in most cases it's the least significant bits that count.)

The iNES format specifies a CHR-ROM size of 0 to mean 8k of CHR-RAM. The CHR data ends up being stored somewhere in the PRG-ROM and copied over to the CHR-RAM by writes to $2007.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Question about emulating UxROM mapper (mapper 002)

Post by Quietust »

wbrian wrote:- The documentation lists the address for the bank select register as "($8000-$FFFF)". This is confusing because it lists an address range. How should this be interpreted? I'm expecting a fixed memory location.
rainwarrior wrote:The register being mapped to $8000-FFFF means that writes anywhere in that range apply. It's the same register at all those addresses, it's really just responding to the write, and only has to pay attention to one bits worth of the address to see that it's in that particular range (i.e. address & $8000).
In other words, it is a single register which can be accessed from 32,768 different addresses (which, conveniently, happen to be consecutive).

You should be aware that nearly all mappers work this way (since it's less expensive to manufacture), and in many of them the addresses are not consecutive - for example, the MMC3 "register mask" is $E001, which means it has registers at $8000-$9FFE even (bank select at $8000,$8002,$8004,...,$9FFC,$9FFE), $8001-$9FFF odd (bank value at $8001,$8003,$8005,...,$9FFD,$9FFF), $A000-$BFFE even (nametable mirroring), $A001-$BFFF odd (PRG RAM write protection), $C000-$DFFE even (scanline counter value), $C001-$DFFF odd (scanline counter reset trigger), $E000-$FFFE even (scanline counter disable), and $E001-$FFFF odd (scanline counter enable). For cases like that, it's best to either mask the entire address and then switch() across it (e.g. "switch (address & 0xE001) { case 0x8000: ...; case 0x8001: ...; case 0xA000: ...; case 0xA001: ...; ... }") or divide it into larger sections and then subdivide it from there (e.g. have one function for $8000-$9FFF which checks "if (address & 0x1) { ... } else { ... }").
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Question about emulating UxROM mapper (mapper 002)

Post by tokumaru »

Register mirroring is a consequence of partial address deciding. You see, to pinpoint one specific address, one has to watch all 16 address lines, and that takes more resources. If you only have one or a few registers that must be mapped to such a big address space, it's much simpler and cheaper to watch and respond to as few address lines as possible, meaning that most of them are ignored, which results in mirroring.
Post Reply