My emulator's MMC1 giving wrong mirroring values

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
My emulator's MMC1 giving wrong mirroring values
by on (#158314)
Hello,

I am currently currently implementing MMC1 and able to play at least a few of the games without really noticeable glitches.
However when I tried to play Metroid, I found a bug in my emu where it uses an incorrect nametable mirroring for the first tunnel.
The screen just before the bugged tunnel
Image

The bugged tunnel (emu reports that it uses horizontal mirroring)
Image

Nametable view
Image

What could be possible causes for this?


I also added the result from Holy Diver Batman (using M1_P128K.nes) as I believe Metroid has the same ROM layout.
Image
What could the detailed test result "0100" mean?

Legend of Zelda has glitches also but not as bad as the tunnel in Metroid
Image
Image
Image

Thank you!
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158316)
That room in metroid should indeed be using horizontal mirroring (which your nametable view seems to be correctly doing). It doesn't change until a few frames before the door opens, I think; the "bottom" tiles that are clearly incorrect should get written before the mirroring switch (when they are still on the "right" nametable under vertical mirroring).

I'm seeing that the writes take place in the $2C00 address area; are you correctly mirroring writes as well as reads? Is your internal VRAM implemented as only 2k of data, mapped into the address space according to the mirroring, or do you have 4k? That "bottom half" nametable in your view there should already be filled with data before the mirroring switch, and immediately after the switch it should still have the same data as the "right side" had before the switch.
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158317)
I think I only use 2K of actual PPU memory by using bitmasks according to the nametable mirroring
$F7FF <- for vertical mirroring (This ensures that $0800 doesnt get decoded)
$FBFF <- for horizontal mirroring (This ensures that $0400 doesnt get decoded)
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158318)
That's not right: it's not 4K of memory that is selectively disabled. Regardless of whether it's laid out horizontally or vertically, accessing PPU memory at $2C00 accesses the same physical memory, which isn't what masking does.
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158319)
So does that mean that physical address = logical address & bitmask is incorrect?
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158320)
Correct. There are only 2048 physical addresses. Mirroring controls whether bit 11 or 10 of the video memory address is used as bit 10 of the nametable address.

Notice that the detected mapper number in Holy Diver Batman is wrong: MMC1 is mapper 1 (SxROM), not mapper 2 (UxROM). It turns out Holy Diver Batman detects ASIC mappers through their response to writes to mirroring control registers. This should be your first hint that mirroring is messed up.

The following sequence of tests applies to both MMC1 (mapper 1) and Action 53 (mapper 28):

Set mirroring type to 2 (ABAB, vertical mirroring/horizontal arrangement)
Write $AB to $2000, which writes to $000
Write $CD to $2400, which writes to $400
Reading $2800 should produce $AB
Reading $2C00 should produce $CD

Set mirroring type to 3 (AABB, horizontal mirroring/vertical arrangement)
Write $89 to $2000, which writes to $000
Write $EF to $2800, which writes to $400
Reading $2400 should produce $89
Reading $2C00 should produce $EF
EDIT: A typo in this test has been corrected

Set mirroring type to 3
Write $65 to $2000
Write $43 to $2800
Set mirroring type to 2
Reading $2000 should produce $65
Reading $2400 should produce $43
Reading $2800 should produce $65
Reading $2C00 should produce $43
Set mirroring type back to 3
Reading $2000 should produce $65
Reading $2400 should produce $65
Reading $2800 should produce $43
Reading $2C00 should produce $43

[Do you understand why each value in this sequence is read back? If not, what's the first thing you misunderstood?]
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158323)
Ok I'll try to understand :)

Quote:
Set mirroring type to 2 (ABAB, vertical mirroring/horizontal arrangement)
Write $AB to $2000, which writes to $000
Write $CD to $2400, which writes to $400
Reading $2800 should produce $AB
Reading $2C00 should produce $CD

I'm okay with this one

Quote:
Set mirroring type to 3 (AABB, horizontal mirroring/vertical arrangement)
Write $89 to $2000, which writes to $000
Write $EF to $2800, which writes to $400
Reading $2800 should produce $89
Reading $2C00 should produce $EF

"Reading $2800 should produce $89" -> shouldn't this one be $2400 (for horizontal mirroring)?

Quote:
Set mirroring type to 3
Write $65 to $2000
Write $43 to $2800
Set mirroring type to 2
Reading $2000 should produce $65
Reading $2400 should produce $43
Reading $2800 should produce $65
Reading $2C00 should produce $43
Set mirroring type back to 3
Reading $2000 should produce $65
Reading $2400 should produce $65
Reading $2800 should produce $43
Reading $2C00 should produce $43

So applying masking here (as if I'm my own emulator)
1. Set mirroring type to 3 (mask = $FBFF)
2. Write $65 to $2000
3. Write $43 to $2800
4. Set mirroring type to 2 (mask = $F7FF)
5. Reading $2000 should produce $65 -> Returns $65 ($2000 & $F7FF)
6. Reading $2400 should produce $43 -> Returns $2400 (??) ($2400 & $F7FF == $2400)
.. No need to continue further..

Now I see the problem with masking!
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158324)
One way of looking at mirroring is that it's a way of remapping the two highest bits of the address.
Code:
15 bit  8 7  bit  0
--------- ---------
0010 nnaa aaaa aaaa  <  nametable read/write address


The bottom 10 bits are used as is for accessing nametables, but the top 2 bits are used to select which nametable to use. The practice of "mirroring" remaps the 4 possible combinations of those 2 bits to the internal VRAM. For example, if you used those two bits for a lookup table, some common mirroring modes might look like:
Code:
mirroring[4] = { 0, 1, 0, 1 }; // vertical mirroring
mirroring[4] = { 0, 0, 1, 1 }; // horizontal mirroring
mirroring[4] = { 0, 0, 0, 0 }; // single screen 0 mirroring
mirroring[4] = { 1, 1, 1, 1 }; // single screen 1 mirroring

You can replace those two bits "nn" with the value looked up from your mirroring table, before using the address to make a read or write. You don't necessarily have to use a lookup table, but any equivalent implementation should work.

It's a little more complicated with mappers that have 4-screen mirroring, or can otherwise map CHR-ROM or CHR-RAM into the nametable space, but this is a little more obscure, and I'm sure you can figure it out when you get there.

On the cartridge, simple mirroring is implemented by physically connecting the 10th or 11th CHR address bit to bit 10 of the VRAM address. The 10th CHR address gives a 0,1,0,1 pattern (vertical mirroring), and the 11th CHR address line gives a 0,0,1,1 pattern (horizontal mirroring), and connecting that output directly to VRAM's 10th bit address directly selects the 1k page. (Reference: Wiki: Mirroring)
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158336)
breathermachine wrote:
Ok I'll try to understand :)

Quote:
Set mirroring type to 3 (AABB, horizontal mirroring/vertical arrangement)
Write $89 to $2000, which writes to $000
Write $EF to $2800, which writes to $400
Reading $2800 should produce $89
Reading $2C00 should produce $EF

"Reading $2800 should produce $89" -> shouldn't this one be $2400 (for horizontal mirroring)?

Oops, my bad. The first read was supposed to be from $2400. I have fixed this above.

rainwarrior wrote:
For example, if you used those two bits for a lookup table, some common mirroring modes might look like

And in fact, some mappers let the program fill that lookup table manually. MMC5 is one of them. There are other funky mirroring methods such as diagonal (ABBA) and L-shaped (ABBB) with their own purposes.
Re: My emulator's MMC1 giving wrong mirroring values
by on (#158365)
Finally made it to work (as well as one-screen mirroring for MMC1 and AxROM). Thanks guys!