MMC5 problems...

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

natt
Posts: 76
Joined: Fri Oct 26, 2012 5:27 pm

Re: MMC5 problems...

Post by natt »

The left and right thirds of the screen are 4 tiles or so too high, but the center portion is much worse. Almost seems like a PPUADDR problem?

In any case, exattr mode seems to be applying consistently. If you can walk around in the opening town of Just Breed without anything looking wrong, exattr mode is probably working right.
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: MMC5 problems...

Post by Zepper »

IRQ timing?
natt
Posts: 76
Joined: Fri Oct 26, 2012 5:27 pm

Re: MMC5 problems...

Post by natt »

The title screen in question doesn't have any splitscreening going on (exattr lets it show all of those tiles without needing a midframe bankswitch).
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: MMC5 problems...

Post by Disch »

I wonder if you are somehow using the X part of the scroll as the Y part? That'd be weird because nothing on the MMC5 has any impact on the scroll (except for the splitscreen mode stuff... but you're not doing that yet I assume).
User avatar
Anes
Posts: 621
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: MMC5 problems...

Post by Anes »

Disch wrote:I wonder if you are somehow using the X part of the scroll as the Y part? That'd be weird because nothing on the MMC5 has any impact on the scroll (except for the splitscreen mode stuff... but you're not doing that yet I assume).
Mmm... i don't get it. I mean my fetchTile() routine is not changing scroll at all.

Anyway here is my poor code thats fetch a mmc5 tile:

Code: Select all

void FetchTileMmc5(int cc)
{
extern MMC5 Mmc5;
extern pu8 g_pChrRom;

	switch (cc & 0x07)
	{
	case 0:
		Ppu.pt_addr = 0x2000 | (Ppu.addr & 0x03FF);
		break;

	case 1:
		Ppu.NTIndex = ReadPpuMem(Ppu.pt_addr);
		Ppu.NTIndex <<= 4;
		break;
	
	case 3:
		Mmc5.ex1 = ReadMmc5ExtraRam(Ppu.pt_addr);
		Ppu.AT = Mmc5.ex1;
		Ppu.AT >>= 6;
		break;

	case 4:
		Ppu.pt_addr = Ppu.NTIndex | ((PPPUADDR)(&Ppu.addr ))->FineY;
		break;

	case 5:
		Mmc5.addr = Mmc5.upper_chr << 18;
		Mmc5.addr |= (Mmc5.ex1 & 0x3F) << 12;
		Ppu.lPT0 = g_pChrRom[((Ppu.pt_addr /*& 0xFFF*/) | Mmc5.addr) & (Mmc5.chr_size - 1)];
		break;
	
	case 6:
		Ppu.pt_addr |= 0x08;
		break;

	case 7:
		Ppu.lPT1 = g_pChrRom[((Ppu.pt_addr /*& 0xFFF*/) | Mmc5.addr) & (Mmc5.chr_size - 1)];

		Ppu.PT0 |= Ppu.lPT0;
		Ppu.PT1 |= Ppu.lPT1;
		Ppu.lAT0 = Ppu.AT & 0x01; 
		Ppu.lAT1 = (Ppu.AT & 0x02) >> 1; 
		break;
	}
}
I know it's a mess and is partial.
The only thing to say here is that ((PPPUADDR)(&Ppu.addr ))->FineY is a pointer to a bit structure that represents the PPU ADDR.
ANes
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: MMC5 problems...

Post by Disch »

Since your code does not check for Ex1 mode, I assume it is only called in Ex1 mode.


Code: Select all

Ppu.pt_addr = 0x2000 | (Ppu.addr & 0x03FF);
You're losing the nametable bits. You probably meant & 0x0FFF


I don't see anything wrong apart from that.
User avatar
Anes
Posts: 621
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: MMC5 problems...

Post by Anes »

Disch wrote:Since your code does not check for Ex1 mode, I assume it is only called in Ex1 mode.


Code: Select all

Ppu.pt_addr = 0x2000 | (Ppu.addr & 0x03FF);
You're losing the nametable bits. You probably meant & 0x0FFF


I don't see anything wrong apart from that.
No, it still has problems... f**n bakground.... i have to check in other places of my code.
Thanks.
ANes
User avatar
Anes
Posts: 621
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: MMC5 problems...

Post by Anes »

Thank to Disch that reviewed my code UW now runs.
I still have two problems:

1) UW gets hang when it enters the first level:
Image
Basically the game is making a JMP Absolute to the same addr. This makes a loop forever.
I have checked for MMC5 interrupts and the game disables it and at the same time is Executing a SEI, so IRQ never executes.
Another thing to mention is that is disabling NMI trough a write to $2000.
So how can it get out of that infinite loop?
Any clue??

2) BK of Ancient China:
Image

Disch's and the Wiki says:
Test ROM Notes:
---------------------------
- Bandit Kings of Ancient China writes PRG-RAM through the $8000+ ROM area. Failure to emulate this causes
corruption when the background is restored on the world map.
I think that is happening. I really dont understand the "$8000 + ROM area".
ANes
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: MMC5 problems...

Post by Disch »

Bandit Kings is probably swapping RAM into the $8000-BFFF area... rather than swapping ROM. See the high bit of the PRG swap regs. It's possible you are always swapping in ROM, which would explain this bug.

This might also be the cause of your UW bug, but I don't know for sure.
User avatar
Anes
Posts: 621
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: MMC5 problems...

Post by Anes »

$5115 swaps $8000 - $BFFF can only be swapped in program mode "1" or "2" and UW nevers change it. It sticks to "3"!!
Does program mode affect prg-ram swapping? I tested my emu not affecting it and have the same results.
I will keep checking...
ANes
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: MMC5 problems...

Post by Disch »

$5115 swaps $8000 - $BFFF can only be swapped in program mode "1" or "2" and UW nevers change it. It sticks to "3"!!
$5115 is somewhat irrelevent. In any mode, you're able to swap out PRG, right? So any time you swap PRG, the high bit determines whether to select RAM or ROM.

The only exception is $5117 .. which will always select ROM (note this also means PRG mode 0 will only select ROM, since $5117 is the only swap reg used in that mode).

ROM/RAM can be selected in any other mode (modes 1-3)
Does program mode affect prg-ram swapping? I tested my emu not affecting it and have the same results.
It affects which registers are used and how. If any of the $5114-5116 registers are being used... they can select ROM or RAM. Whether or not those registers are used depends on the mode.
User avatar
Anes
Posts: 621
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: MMC5 problems...

Post by Anes »

My code looks like this:

Code: Select all

	case 0x5113:
		Mmc5.r5113 = (data & 0x07);
		page_kb32 = Mmc5.r5113 * KB_8;
		SwapMmc5Ram(page_kb32, 0x6000, 0x2000);
		MapMemory(0x6000, 0x7FFF, ReadMmc5Extra64, WriteMmc5Extra64);
		break;

	case 0x5114:
		if ((data & 0x80))
		{
			if (Mmc5.prg_mode == 3)
			{
				MapMemory(0x8000, 0x9FFF, ReadMapperPrgMem, WriteMapperPrgMem);
				SwapPrg4K(0x8000, (data & 0x7F) & (((Mapper.last_prg)* 4)-1), 0x2000);
			}
		}
		else 
		{
			if (Mmc5.prg_mode == 3)
			{
				page_kb32 = (data & 0x07) * KB_8;
				SwapMmc5Ram(page_kb32, 0x8000, 0x2000);
				MapMemory(0x8000, 0x9FFF, ReadMmc5Extra64, WriteMmc5Extra64);
			}
		}
		break;

	case 0x5115:
			if ((data & 0x80))
			{
				if (Mmc5.prg_mode == 1 || Mmc5.prg_mode == 2) 
				{
					MapMemory(0x8000, 0xBFFF, ReadMapperPrgMem, WriteMapperPrgMem);
					SwapPrg4K(0x8000, ((data & 0x7F) >> 1) & (((Mapper.last_prg)* 2)-1), 0x4000);
				}
				else
				if (Mmc5.prg_mode == 3) 
				{
					MapMemory(0xA000, 0xBFFF, ReadMapperPrgMem, WriteMapperPrgMem);
					SwapPrg4K(0xA000, (data & 0x7F) & (((Mapper.last_prg)* 4)-1), 0x2000);
				}
		
			}
			else 
			{
				if (Mmc5.prg_mode == 1 || Mmc5.prg_mode == 2) 
				{
					page_kb32 = (data & 0x07) * KB_8;
					SwapMmc5Ram(page_kb32, 0x8000, 0x4000);
					MapMemory(0x8000, 0xBFFF, ReadMmc5Extra64, WriteMmc5Extra64);
				}
				else
				if (Mmc5.prg_mode == 3) 
				{
					page_kb32 = (data & 0x07) * KB_8;
					SwapMmc5Ram(page_kb32, 0xA000, 0x2000);
					MapMemory(0xA000, 0xBFFF, ReadMmc5Extra64, WriteMmc5Extra64);
				}
			}
		
		break;

	case 0x5116:
		if ((data & 0x80))
		{
			switch (Mmc5.prg_mode)
			{
			case 2:
				MapMemory(0xC000, 0xDFFF, ReadMapperPrgMem, WriteMapperPrgMem);
				SwapPrg4K(0xC000, (data & 0x7F) & (((Mapper.last_prg)* 4)-1), 0x2000);

			case 3:
				MapMemory(0xC000, 0xDFFF, ReadMapperPrgMem, WriteMapperPrgMem);
				SwapPrg4K(0xC000, (data & 0x7F) & (((Mapper.last_prg)* 4)-1), 0x2000);
				break;
			}
		}
		else 
		{
			switch (Mmc5.prg_mode)
			{
			case 2:
			case 3:
				page_kb32 = (data & 0x07) * KB_8;
				SwapMmc5Ram(page_kb32, 0xC000, 0x2000);
				MapMemory(0xC000, 0xDFFF, ReadMmc5Extra64, WriteMmc5Extra64);
				break;
			}
		}
		break;

	case 0x5117:
		switch (Mmc5.prg_mode)
		{
		case 0:
			MapMemory(0x8000, 0xFFFF, ReadMapperPrgMem, WriteMapperPrgMem);
			SwapPrg4K(0x8000, ((data & 0x7F) >> 2) & (Mapper.last_prg - 1), 0x8000);
			break;

		case 1:
			MapMemory(0xC000, 0xFFFF, ReadMapperPrgMem, WriteMapperPrgMem);
			SwapPrg4K(0xC000, ((data & 0x7F) >> 1) & (((Mapper.last_prg)* 2)-1), 0x4000);
			break;
		
		case 2:
		case 3:
			MapMemory(0xE000, 0xFFFF, ReadMapperPrgMem, WriteMapperPrgMem);
			SwapPrg4K(0xE000, (data & 0x7F) & (((Mapper.last_prg)* 4)-1), 0x2000);
			break;

		}
		break;
I can't find any error, and there are.
MapMemory(from, to, pFunRead, pFunWrite): as it names implies map the memory into an array of function pointers.
SwapPrg4K(addr, bank, size): It does the ROM swap.
SwapMmc5Ram(page, wherein, size):Takes the caluclated page and directly memcpy to "wherein" into a plain 64K of "size".

You said i can avoid prg-mode when i swap prg-ram. I have tried commenting:

Code: Select all

if (Mmc5.prg_mode == 3) 
"ifs" and "switchs" and no result.
ANes
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: MMC5 problems...

Post by Disch »

I didn't look over the code too closely (kind of at work, so I can only take quick breaks). However, you are showing me 2 things that are kind of alarming.

#1:
SwapMmc5Ram(page, wherein, size):Takes the caluclated page and directly memcpy to "wherein" into a plain 64K of "size".
memcpy is a bad sign. There is no copying going on when you swap. What's happening is the chip is modifying the address lines on access.

The same memory could be swapped into 2 different places. For example.. if it swaps RAM page 1 into both $8000 and $6000... then those two areas would effectively be "mirrored". Writes to $6000 would be visible at $8000 and vice versa.


#2:

You are doing complex logic in your register writes, rather than a "sync" style function. This will work as long as the game does not switch modes... but as soon as it does, you'll either have to duplicate all that logic, or you will have the wrong stuff swapped in.

When the game changes modes, it's as if it "reswaps" all pages. This is often implemented as a "sync" function. IE when the game writes to the mode, you change the mode var, then 'sync'. And when it writes to a PRG swap reg, you just modify a variable and then 'sync' again. The 'sync' function is the one that would be examining the mode and swapping out all the pages.

Also note that this is not MMC5 specific, but applies to all mappers.
User avatar
Anes
Posts: 621
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: MMC5 problems...

Post by Anes »

I did one thing: i "marged" with my mapping engine.... i mean i used SwapPrg4K() to swap prg-ram.
UW Works (with some graphics glitches):
Image
and BK of Ancient China now looks good.
The thing is i have a 64kb that's in the mapper... if i knew the prg-ram size would be prominent, but the wiki says that byte "8" should indicate that and roms out there have only "0". But, but it says that emulators even don't use this byte.
What do i do?
ANes
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: MMC5 problems...

Post by tepples »

In NES 2.0, the RAM size field is byte 10.
Post Reply