MMC1 question

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
MMC1 question
by on (#16014)
Ho

Ive started emulating some chips.. MegaMan2 runs perfectly but ive problems with Zelda and Metroid they hang so it must be some problem with the ROM switching but from what Ive read this is how it should be done. Here is my code for a write:

Code:
void NES_CPU_Mapper1(u32 Address, u8 Data)
{
   u32 Temp;

   // Mapper 1 (MMC1)
   if (Address >= 0x8000 && Address < 0x10000)
   {
      if (Data & BIT(7))
      {
         g_NesCPUMapper.Register0 |= BIT(2) | BIT(3);
         g_NesCPUMapper.Write = 0;
      }
      else
      {
         if (g_NesCPUMapper.Write == 4)
         {
            g_NesCPUMapper.Data |= (Data & 0x1) << g_NesCPUMapper.Write;

            if (Address < 0xA000)      // Register 0
            {
               g_NesCPUMapper.Register0 = g_NesCPUMapper.Data;
            }
            else if (Address < 0xC000)   // Register 1
            {
               
               if (g_NesCPUMapper.Register0 & BIT(4))
               {
                  NES_CPU_SetCHRROMBank4KB(0, g_NesCPUMapper.Data);
               }
               else
               {
                  NES_CPU_SetCHRROMBank4KB(0, g_NesCPUMapper.Data*2+0);
                  NES_CPU_SetCHRROMBank4KB(1, g_NesCPUMapper.Data*2+1);
               }
            }
            else if (Address < 0xE000)   // Register 2
            {
               if (g_NesCPUMapper.Register0 & BIT(4))
                  NES_CPU_SetCHRROMBank4KB(1, g_NesCPUMapper.Data);
            }
            else                  // Register 3
            {
               Temp = ((g_NesCPUMapper.Register0 >> 2) & 0x3);
               if (Temp == 2)
               {
                  NES_CPU_SetPRGROMBank16KB(0, 0);
                  NES_CPU_SetPRGROMBank16KB(1, g_NesCPUMapper.Data);
               }
               else if (Temp == 3)
               {

                  NES_CPU_SetPRGROMBank16KB(0, g_NesCPUMapper.Data);
                  NES_CPU_SetPRGROMBank16KB(1, g_NesPRGROMBankCount - 1);
               }
               else
               {
                  NES_CPU_SetPRGROMBank16KB(0, (g_NesCPUMapper.Data & ~0x1) + 0);
                  NES_CPU_SetPRGROMBank16KB(1, (g_NesCPUMapper.Data & ~0x1) + 1);
               }
            }

            g_NesCPUMapper.Data = 0;
            g_NesCPUMapper.Write = 0;
         }
         else
         {
            g_NesCPUMapper.Data |= (Data & 0x1) << g_NesCPUMapper.Write;
            g_NesCPUMapper.Write++;
         }
      }
   }
}


Do you see any problems?
thanks

by on (#16015)
Good documentation on MMC1 is here: http://nesdevwiki.ath.cx/index.php/MMC1

By looking at it quickly, I can see reg0 is incomplete: you forgot the mirroring control, and mind that the other 3 registers also need to be updated after a write to reg0.
Re: MMC1 question
by on (#16016)
Could be that you're only swapping CHR-ROM when Zelda (and probably Metroid) both use CHR-RAM. (At least that what your function names suggest)

What I do for my mappers is I have a generic "SwapCHR" function which will call SwapCHRROM() if CHR-ROM is present, otherwise it will call SwapCHRRAM().

Also, you should be tracking the internal registers, and updating PRG/CHR on a write to the first register (hap was hinting at this). For example, it would be perfectly legal and acceptable for the game to write the desired 8k CHR page to $A000 while in 4k swapping mode... THEN change to 8k mode. From the looks of your source, you would not be handling this properly since you are only swapping when the game writes to CHR regs.

It also helps to keep track of values written just for savestate purposes.

If it would help to see an example of what I'm talking about... here's my MMC1 code:

http://disch.panicus.org/nes_mpr001.cpp

by on (#16019)
If a game use CHR RAM I can't understand what happens when a switch is made? isnt it just ignored? or is data taken from PRG ROM?

and what is the "c"-parameter sent to your Write function?

by on (#16020)
CHR RAM on SNROM and similar carts has two banks, each 4 KB in size. Most games just set up CHR bank mode 0 and use them as one unit, but in bank mode 1, they could be swapped or assigned to the same bank.

by on (#16022)
If Zelda and Metroid hang, it's probably because you're forgetting to map RAM at $6000-$7FFF.

by on (#16025)
Should WRAM be mapped to that location? I thought it was SRAM always?
And metroid don't use SRAM at all I think. Ive tried some other games castlevania2 works, MegaMan2 works, I want to try another game that uses SRAM and MMC1. Do you know such a game?

by on (#16026)
n6 wrote:
Should WRAM be mapped to that location? I thought it was SRAM always?


"WRAM" and "SRAM" are the same thing - most people use the latter to refer to it when it has a battery connected.
Personally, I prefer to just call it "PRG-RAM" and then say whether or not there's a battery.

by on (#16027)
Okey so WRAM is always mirrored at 0x6000? even if the game use or not use SRAM its mapped, right?

by on (#16028)
n6 wrote:
Okey so WRAM is always mirrored at 0x6000? even if the game use or not use SRAM its mapped, right?


Mirrored? No.
Mapped? Most definitely yes - with the existing iNES ROMs, there is no way to tell whether a game does or does not have RAM at $6000-$7FFF, so you pretty much have to always map it.
UNIF handles this properly by indicating the board name (from which you can determine whether or not there is any RAM), but has other issues which prevent its widespread usage.