About MMC1..

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Muchaserres
Posts: 96
Joined: Sat Nov 13, 2004 6:25 am

About MMC1..

Post by Muchaserres » Sun Nov 04, 2007 3:17 pm

Hi all,

According to the wiki, writting any MMC1 register with a value whose highest bit is set makes the control register to be ORed with 0x0C. As far as I understand it, this only affects CHR-ROM bank mode, as PRG-ROM bits are left untouched. The point here is that I don't see why the wiki states, literally, "..locking PRG ROM at $C000-$FFF to the last bank.". So, although the bank mode is not modified, the PRG banks are swapped while CHR banks are left intact.. Why is that?

I know MMC1 reset state is not known at all but.. would it be accurate to apply a reset shift register as MMC1's initial state?

On the other hand, I think there's a typo in "Variants" section. Shouldn't SXROM combination be "512KB of PRG ROM and 16KB of PRG RAM" instead of "512KB of PRG ROM and 32KB of PRG RAM" (as SOROM chooses between TWO 8KB banks)?

One more thing. Which exact registers and bits are "upper CHR bank select line" and "second-highest CHRbank select line" referring to in "Variants" section?

Thx.

tepples
Posts: 22361
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Sun Nov 04, 2007 3:31 pm

You must be misreading the wiki page. It states that ORing with $0C affects only the PRG bank mode ($08) and PRG bank location ($04), not the CHR bank mode ($10) or the mirroring mode ($03).

Code: Select all

4bit0
-----
CPRMM
|||||
|||++- Mirroring (0: one-screen, lower bank; 1: one-screen, upper bank;
|||               2: vertical; 3: horizontal)
||+--- PRG ROM bank location (0: switch 16 KB at $C000; 1: switch 16 KB at $8000
||                            only used when PRG bank mode bit below is set to 1)
|+---- PRG ROM bank mode (0: switch 32 KB at $8000, ignoring low bit of bank number;
|                         1: switch 16 KB at address specified by location bit above)
+----- CHR ROM bank mode (0: switch 8 KB at a time; 1: switch two separate 4 KB banks)
Last edited by tepples on Sun Nov 04, 2007 4:09 pm, edited 1 time in total.

Muchaserres
Posts: 96
Joined: Sat Nov 13, 2004 6:25 am

Post by Muchaserres » Sun Nov 04, 2007 3:50 pm

Whoops! I confused ORing with ANDing, although I had it correctly implemented in my emu.. XD

Question #1 solved.

Thx.

User avatar
Bregalad
Posts: 8025
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad » Mon Nov 05, 2007 10:35 am

"Resetting" the MMC1 accurately reset its shift register, and SXROM has 32 KB of SRAM (allthrought I cannot check if all 32KB is acessible because I have not a such cart, I'm pretty sure it is because both game that uses it use only 16 KB of SRAM, but one uses banks 0 and 2 and the other banks 0 and 1, if I remember correctly).

Muchaserres
Posts: 96
Joined: Sat Nov 13, 2004 6:25 am

Post by Muchaserres » Mon Nov 05, 2007 12:23 pm

I recall having read somewhere in the forums someone (Disch? Blargg?) talking about some partial tests done on MMC1 reset state, from which it was told the initial values for the regs are something like

Code: Select all

Regs[ 0 ] = 0x0F;
Regs[ 1 ] = Regs[ 2 ] = Regs[ 3 ] = 0x1F;
By doing so, several games don't even start running, while using 0x00 for all of them seems to work fine.

On the SRAM side, ogghh.. it is quite a pain to implement this mapper properly for programs defined by the iNES header, as every MMC1 revision interprets differently every bit of its registers. How do you guys work this problem out in your emus?

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Mon Nov 05, 2007 2:25 pm

Muchaserres wrote:I recall having read somewhere in the forums someone (Disch? Blargg?)
I think it was Blargg. Anyways:

-) Contents of all registers are unreliable at startup (they contain powerup garbage, just like unprepped RAM does)

-) Some MMC1 revisions (don't know which) OR reg0 with 0x0C on startup. Several games rely on this.

-) Some MMC1 revisions do not have the WRAM disable bit (bit 4 of reg3 does nothing). Some games (Kid Icarus comes to mind) do not clear the bit before attempting to access WRAM -- so if you set this reg to $1F, that could be why these games are not even starting.

-) Other MMC1 revisions have the WRAM disable bit. On some revisions its initial state is unreliable, on others its set initially, and on others its clear initially (iirc)


In my emu I zero everything except reg0, which I set to $0C.

as every MMC1 revision interprets differently every bit of its registers. How do you guys work this problem out in your emus?
Here's snippits from my source:

Code: Select all

int NESMpr001::Load()
{
	NESMapperMMC1::Load();

	static const ch_t* vnames[MMC1_COUNT] = {
		shT("Generic MMC1 (256k PRG, 8k RAM)"),
		shT("SUROM (512k PRG, 8k RAM)"),
		shT("SOROM (256k PRG, 16k RAM)"),
		shT("SXROM (512k PRG, 32k RAM)")
	};

	mSubMpr.nVal1Count =			MMC1_COUNT;
	mSubMpr.szVal1Names =			vnames;

	pFileInfo->nPRGRAMSize = 0x8000;		// SXROM uses 32k

	return 0;
}

void NESMpr001::SyncRAM(int cu)
{
	NESMapperMMC1::SyncRAM(cu);

	switch(mSubMpr.nVal1)
	{
	case MMC1_GENERIC:
	case MMC1_SUROM:
		SwapPRG_8k(6,0,0,1);
		break;

	case MMC1_SOROM:
		if(nRegs[0] & 0x10)		SwapPRG_8k(6,(nRegs[1] & nRegs[2] & 0x10) >> 4,0,1);
		else					SwapPRG_8k(6,(nRegs[1] >> 3) & 1,0,1);
		break;

	case MMC1_SXROM:
		if(nRegs[0] & 0x10)		SwapPRG_8k(6,(nRegs[1] & nRegs[2] & 0x0C) >> 2,0,1);
		else					SwapPRG_8k(6,(nRegs[1]            & 0x0C) >> 2,0,1);
		break;
	}
}

void NESMpr001::SyncPRG(int cu)
{
	if(cu)		CUAPU();

	switch(mSubMpr.nVal1)
	{
	case MMC1_GENERIC:
	case MMC1_SOROM:
		NESMapperMMC1::SyncPRG(0);
		break;

	case MMC1_SUROM:
	case MMC1_SXROM:
		if(nRegs[0] & 0x10)		MMC1PRG(0x0F,(nRegs[1] & nRegs[2] & 0x10),0);
		else					MMC1PRG(0x0F,(nRegs[1]            & 0x10),0);
		break;
	}
}
NESMpr001 is derived from NESMapperMMC1 which handles basic MMC1 functionality (combining the 5 writes into 1 full write, setting internal registers, etc). The SyncXXX functions are virtual and are called after every complete register write. (This inheritance setup also makes mapper 105 much easier)

The strings and junk in my "Load" function eventually fed to mapper config box which can be opened through the UI:

Image

I also plan on eventually setting which to use automatically via a CRC.

tepples
Posts: 22361
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Mon Nov 05, 2007 2:49 pm

Disch wrote:The strings and junk in my "Load" function eventually fed to mapper config box which can be opened through the UI:

Image
Wouldn't switching between SNROM and SUROM be automatic based on PRG size, as with SOROM vs. SXROM? So then you could simplify it down to one dialog box for SN vs. SO (PRG size <= 256 KiB) and one for SU vs. SX (larger PRG).

Another tip: User interface guidelines recommend using verbs as the labels of buttons that do something, to reinforce to the user that they do something. This means "OK" could become "Apply and Restart".
I also plan on eventually setting which to use automatically via a CRC.
Out of whose database?

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Mon Nov 05, 2007 3:18 pm

tepples wrote:Wouldn't switching between SNROM and SUROM be automatic based on PRG size, as with SOROM vs. SXROM? So then you could simplify it down to one dialog box for SN vs. SO (PRG size <= 256 KiB) and one for SU vs. SX (larger PRG).
I suppose I could do that. I thought about it at first but for whatever reason decided against it.

Removing 2 options doesn't make the box much simpler... I mean 4 options is hardly overwhelming. Plus removing options is removing options. That is -- less flexibility. And I don't really expect people to go putzing around with these options unless they really know what they're doing anyway. If there's a CRC in there, they won't need to.
Another tip: User interface guidelines recommend using verbs as the labels of buttons that do something, to reinforce to the user that they do something. This means "OK" could become "Apply and Restart".
Good idea.

*does*
Out of whose database?
Probably will start one of my own. I plan on having it stored externally (in a text file or something) so that people can add their hacks or whatever to it.

tepples
Posts: 22361
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Mon Nov 05, 2007 4:00 pm

Disch wrote:Plus removing options is removing options. That is -- less flexibility.
Disch wrote:And I don't really expect people to go putzing around with these options unless they really know what they're doing anyway. If there's a CRC in there, they won't need to.
Are you intending your emulator to be used mostly for running copies of commercial games or mostly for running homebrew?

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Mon Nov 05, 2007 4:06 pm

EDIT -- blah

I don't feel like debating/arguing/defending my design to you. Thanks for the suggestions. I'll leave it at that.

tepples
Posts: 22361
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Mon Nov 05, 2007 4:13 pm

Point taken.

Anyone else need a point of the MMC1's operation clarified?

User avatar
Bregalad
Posts: 8025
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad » Tue Nov 06, 2007 11:10 am

I don't think the MMC1 has an random state at startup, as most games only have the reset code in the last bank, so technically they relies on the last bank to be switced in $c000-$ffff on power-on.
Everything else may be reliable or not, depending on the version of the MMC1. SRAM protection is purely hardware stuff, I don't think many game will turn this on, and write to SRAM while excepting writes to be ignored. I guess this can be pretty much ignored when it comes to emulation, but developpers should still know about that bit, so that they don't set it and exept the SRAM to work as usual on real hardware (this will most likely work in most emus, and proabely with MMC1 and MMC1A too).

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Tue Nov 06, 2007 11:20 am

Bregalad wrote:I don't think the MMC1 has an random state at startup, as most games only have the reset code in the last bank, so technically they relies on the last bank to be switced in $c000-$ffff on power-on.
I thought that too, until I was corrected

Later revisions do start with those PRG mode bits set (which puts the last 16k at $C000), but earlier ones do not.

From an emulator standpoint -- I would just set those bits at startup all the time.
Everything else may be reliable or not, depending on the version of the MMC1. SRAM protection is purely hardware stuff, I don't think many game will turn this on, and write to SRAM while excepting writes to be ignored. I guess this can be pretty much ignored when it comes to emulation,
I don't know of any MMC1 games that do it, but I believe Low G Man (MMC3) relies on WRAM disabling.

User avatar
Bregalad
Posts: 8025
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad » Tue Nov 06, 2007 11:29 am

Low G Man relies on SRAM to be absent (and not to be disabled) and to return open bus.
I'm 100% sure the MMC1A has the last bank set on startup, then, only the first MMC1 have a completely unreliable state (Original Zelda, Metroid, Kid Icarus and possibly a couple of other games should then have multiple reset code).

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Tue Nov 06, 2007 12:57 pm

Bregalad wrote:Low G Man relies on SRAM to be absent (and not to be disabled) and to return open bus.
Perhaps. I suppose it would work the same if you simply don't give the game SRAM at all.

At any rate, if you emulate MMC3's WRAM disable, it doesn't matter if you give the game SRAM or not because Low G Man disables it.

Post Reply