Details of MMC5 operation

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderator: Moderators

Post Reply
User avatar
krzysiobal
Posts: 1037
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland
Contact:

Details of MMC5 operation

Post by krzysiobal »

While creating repro of Super Mario All Stars for MMC5, I had to implement MMC5 in FPGA. For some unknown reason, creators of this cartridge used the ability of MMC5 to supply diffrent CHR banks for sprites & background. Of course they also use the IRQ, so I come back into trouble of thinking how MMC5 scanline detector works.
Fortunately I have Just Breed MMC5 cartridge, so using KrzysioKazzo i was able to research MMC5 features with cycle acuracy
Image

Before I started any research, I rev'ed the board to confirm if the wiki data is correct. I found two bugs:
Image Image Image
1. pin 28 is PPU-!A13, not PPU-A13 as states wiki
2. one of the resistors in amplifier circuit is 6.8k (but it might vary from board to board I think)

I am also very curious about the unconnected pins. They are wired and cut out of edge from board, this is super crazy. Also, multimeter test shows internal connection. I think they might be related to the WRAM.
Image

----

Ok, now some research about the MMC5 itself:
0. Multiplier ($5205/$5206) -> after writing A and B, low(A*B) and high(A*B) can be read immediatelly on next cpu cycle (no need to wait 8 cycles like in mapper90). This means that the whole product is calculated as combinatorial function and it requires quite a lot of ASIC resources.
The 8 cycle delay in mapper 90 is because after every cycle, each succesive bit of B is multiplied by A and added to the result causing much less resource need.

1.Check if sequence of two PPU reads from same address at row will trigger MMC5's scanline detector
It won't

Code: Select all

public byte[] cpu_read(long start_address, int bytes_to_read)
void cpu_write(long start_address, byte[] bytes_to_write);
public byte[] ppu_read(long start_address, int bytes_to_read);
public void ppu_write(long start_address, byte[] bytes_to_write);
public int read_irq(); //reads !IRQ line (0=irq asserted, 1=not asserted), this does not produce any cpu cycle
public void cpu_m2_constant_clocking(bool clocking_enabled); //if clocking_enabled=false -> there won't be any cpu/ppu cycles during idle time, if
 clocking_enabled=true, there will be CPU read at $0000 as idle cycle



cpu_m2_constant_clocking(false); 
	cpu_read(0x5204, 1); //clear any interrupt if pending
	cpu_write(0x5203, new byte[] {10}); //generate irq at scanline 10

	string result = "";
	byte r0x5204;

	for (int i = 0; i < 20; ++i) {
		r0x5204 = cpu_read(0x5204, 1)[0];
		result += String.Format("{0:x2} ", r0x5204);

		ppu_read(1 << 13, 1);
		ppu_read(1 << 13, 1);
		ppu_read(0 << 13, 1);
	} 
Output:
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
2.Check if sequence of three PPU reads from same address at row will trigger MMC5's scanline detector
It does

Code: Select all

	string result = "";
	byte r0x5204;
	
	cpu_m2_constant_clocking(false); 
	cpu_read(0x5204, 1); //clear any interrupt if pending
	cpu_write(0x5203, new byte[] {10}); //generate irq at scanline 10

	for (int i = 0; i < 20; ++i) {
		r0x5204 = cpu_read(0x5204, 1)[0];
		result += String.Format("{0:x2} ", r0x5204);

		ppu_read(1 << 13, 1);
		ppu_read(1 << 13, 1);
		ppu_read(1 << 13, 1);     <- this was added
		ppu_read(0 << 13, 1);
	} 
Output:
	00 00 40 40 40 40 40 40 40 40 40 40 c0 40 40 40 40 40 40 40
---
03. Will 3 reads with A13=0 trigger it?
It won't

Code: Select all

	string result = "";
	byte r0x5204;
	
	cpu_m2_constant_clocking(false); 
	cpu_read(0x5204, 1); //clear any interrupt if pending
	cpu_write(0x5203, new byte[] {10}); //generate irq at scanline 10

	for (int i = 0; i < 20; ++i) {
		r0x5204 = cpu_read(0x5204, 1)[0];
		result += String.Format("{0:x2} ", r0x5204);

		ppu_read(0 << 13, 1);         <- change  was made here
		ppu_read(0 << 13, 1);         <- change  was made here
		ppu_read(0 << 13, 1);         <- change  was made here
		ppu_read(1 << 13, 1);         <- change  was made here
	} 
Output:
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
-------------------------------------------------------------------------------------------------
04. Does the PPU address matter or only A13 is checked?
There must be three consecutive fetches of the same address with A13=1 (all bits are checked)

Code: Select all

	string result = "";
	byte r0x5204;
	
	cpu_m2_constant_clocking(false); 
	cpu_read(0x5204, 1); //clear any interrupt if pending
	cpu_write(0x5203, new byte[] {10}); //generate irq at scanline 10

	for (int b = 0; b < 14; ++b) {
		for (int i = 0; i < 20; ++i) {
			r0x5204 = cpu_read(0x5204, 1)[0];
			result += String.Format("{0:x2} ", r0x5204);

			ppu_read((1 << 13) | (1 << b), 1);         <- change  was made here
			ppu_read(1 << 13, 1);
			ppu_read(1 << 13, 1);
			ppu_read(0 << 13, 1);
		}
		result += "\r\n";
	}
Output:
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
	00 00 40 40 40 40 40 40 40 40 40 40 c0 40 40 40 40 40 40 40 
-------------------------------------------------------------------------------------------------
05. What if there are more than 3 fetches per row?
Interrupt was generated earlier.

Code: Select all

	string result = "";
	byte r0x5204;
	
	cpu_m2_constant_clocking(false); 
	cpu_read(0x5204, 1); //clear any interrupt if pending
	cpu_write(0x5203, new byte[] {10}); //generate irq at scanline 10

	for (int i = 0; i < 20; ++i) {
		r0x5204 = cpu_read(0x5204, 1)[0];
		result += String.Format("{0:x2} ", r0x5204);
		
		ppu_read(1 << 13, 1);
		ppu_read(1 << 13, 1);
		ppu_read(1 << 13, 1);
	}
	
Output:
	00 00 40 40 40 c0 40 40 40 40 40 40 40 40 40 40 40 40 40 40 

06. I found it by accident, but if I add one additional CPU read cycle before reading 0x5204 or after writing 0x5203,
the output will be:
00 40 40 40 40 40 40 40 40 40 40 c0 40 40 40 40 40 40 40 40
instead of:
00 00 40 40 40 40 40 40 40 40 40 40 c0 40 40 40 40 40 40 40
so the scanline detector starts working one scanline earlier.

06. What makes MMC5 think that frame rendering has ended
CPU read from from $fffa? -> yes
CPU read from from $fffb? -> yes
CPU write at $fffa/$fffb? -> no
CPU write $00 at $2001 -> no

If there are 3 or more CPU reads between which are no PPU read, MMC5 starts thinking PPU rendering has ended.ppu read
cpu read
cpu read
cpu read <- at beginning of this cycle, mmc5 sets in-frame to 0 (so if this read would be from $5204, it will return 0)

PPU writes does not matter, the following sequence will still set in-frame to 0:
ppu read
cpu read
ppu write
cpu read
cpu read <- at beginning of this cycle, m2 sets in-frame to 0 (so if this read would be from $5204, it will return 0)

---

Later I will check the memory protection bits, because I roughly tested it few days ago and I think that when M2 stops toggling, these bits are automatically set (like if reset happened). No idea how MMC5 checks without help of external detector that this happened.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Details of MMC5 operation

Post by lidnariq »

krzysiobal wrote:I am also very curious about the unconnected pins. They are wired and cut out of edge from board, this is super crazy. Also, multimeter test shows internal connection. I think they might be related to the WRAM.
I assume they're all some sort of validation, but it'd be interesting to figure out what all the bonus pins are. Certainly all the pins actually come out of the package and go to traces (that then fall off the PCB)

I wouldn't be surprised if pins 73 and 75 were "PRG RAM /CE" and "PRG RAM A15". And if one of 29 or 30 were "PPU A13 OR PPU /RD". But that leaves a number of pins.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Details of MMC5 operation

Post by Bregalad »

I am also very curious about the unconnected pins. They are wired and cut out of edge from board, this is super crazy.
The vast majority of Nintendo-made boards have those, this is nothing MMC5 specific.
User avatar
infiniteneslives
Posts: 2104
Joined: Mon Apr 04, 2011 11:49 am
Location: WhereverIparkIt, USA
Contact:

Re: Details of MMC5 operation

Post by infiniteneslives »

Old PCBs often have areas where several traces meet together and then appear to have been drilled through that crossing to electrically disconnect them.

Just a guess, but I think these "crazy" routings allowed for PCB continuity testing prior to drilling step that breaks all the testing connections. Perhaps the traces that run off the edge of the board connected to a testing header of sorts.
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers
User avatar
krzysiobal
Posts: 1037
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland
Contact:

Re: Details of MMC5 operation

Post by krzysiobal »

What about this one?
Image

You really think there has been test pads in the place where there is hole now?
I rather suspect that this is some copy-protection policy. Nintendo ordered big PCB sheets containing more small PCB cartridges on them, with some fake tracks and connections between those small carts and later, they cutted and milled them on their own or in another factory to minimize posibility of leakage.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Details of MMC5 operation

Post by Bregalad »

krzysiobal wrote:What about this one?
I rather suspect that this is some copy-protection policy.
Hahaha ! I like how every single time something is not understood in reverse-engineering, someone comes and claims "this is a form of copy protection".
0. Multiplier ($5205/$5206) -> after writing A and B, low(A*B) and high(A*B) can be read immediatelly on next cpu cycle (no need to wait 8 cycles like in mapper90). This means that the whole product is calculated as combinatorial function and it requires quite a lot of ASIC resources.
Could be, but not necessarily. There is a 4 cycle gap between an STA $abs and an immediately following LDA $abs instruction, so the MMC5 might take advantage of it for its multiplier.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Details of MMC5 operation

Post by lidnariq »

krzysiobal wrote:You really think there has been test pads in the place where there is hole now?
Another possibility is that their EDA software wouldn't let them have a trace that didn't go anywhere, so to silence it they sent it to a connector that they then milled out.
User avatar
infiniteneslives
Posts: 2104
Joined: Mon Apr 04, 2011 11:49 am
Location: WhereverIparkIt, USA
Contact:

Re: Details of MMC5 operation

Post by infiniteneslives »

That's an example of where they all shorted together like I mentioned. Perhaps that massive shorting of signals provided continuity checks at the header that would be off the edge. I'm saying the signals that went off the edge of the board is where the header may have been. This is all just a theory though. I find it hard to believe it's copy protection and Nintendo did post manufacturing. I've wondered if lidnariq's theory might be the case as well, some artifact of early design tools.
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers
User avatar
kevtris
Posts: 504
Joined: Sat Oct 29, 2005 2:09 am
Location: Indianapolis
Contact:

Re: Details of MMC5 operation

Post by kevtris »

krzysiobal wrote: I am also very curious about the unconnected pins. They are wired and cut out of edge from board, this is super crazy. Also, multimeter test shows internal connection. I think they might be related to the WRAM.
Image

Nah the answer is a lot more pedestrian. It's because they need to short all the lines together that they wish to gold plate. There's a shorting bar on the card edge where it plugs into the system, and then more shorting bars around the edges of the board. These cartridge boards use hard gold (vs. ENIG) and this is a plating process, so everything you wish to have gold on needs to be electrically connected.

The boards are plated, then the shorting bars are routed off, breaking all the connections into their separate circuits. You'll find that most if not all of the connections that run off the top/sides of the board are all internal" connections- i.e. signals from the MMC5 to the ROMs or WRAM and signals that do not actually make it back to the card edge. This is found on nearly all (if not all) nintendo-made cartridge boards.
/* this is a comment */
User avatar
infiniteneslives
Posts: 2104
Joined: Mon Apr 04, 2011 11:49 am
Location: WhereverIparkIt, USA
Contact:

Re: Details of MMC5 operation

Post by infiniteneslives »

Ahh that makes a lot more sense. Guess I was right about intentional shorting and off board connection, but for the wrong reasons... Thanks kevtris!
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Details of MMC5 operation

Post by lidnariq »

But why would you need to plate any signals that don't go to the card edge?
User avatar
krzysiobal
Posts: 1037
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland
Contact:

Re: Details of MMC5 operation

Post by krzysiobal »

All vias are gold plated.
User avatar
krzysiobal
Posts: 1037
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland
Contact:

Re: Details of MMC5 operation

Post by krzysiobal »

I accidentally found out that the Super Mario All Stars hack, which uses MMC5 mapper, does not work correctly using my devcart when played on PAL NES (on Dendy & NTSC Famicom it worked fine).

After investigation I found out that interrupt was not launched at all because scanline counter was reset during frame few times and never had chance to approach the value.

Scanline counter is reset when MMC5 sees that rendering was stopped (when seeing CPU access to $FFFA or if there are no PPU read cycles in last three M2 clocks)

While Dendy or Famicom NTSC has 3 : 1 PPU/CPU clock ratio, PAL NES has 3.2 : 1 which caused sometimes unalligned checks. Incrementing it to take into account not last three M2 clocks but five solved the problem, but I am really curious how real MM5 copes with that.
Post Reply