weird MMC1 PRG init problem...

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
etabeta
Posts: 109
Joined: Wed Nov 29, 2006 10:11 am
Location: Trieste, Italy

weird MMC1 PRG init problem...

Post by etabeta »

Hi,

I post this here because I feel like the problem might be something very easy...

however, I'm currently initializing MMC1 emulation by setting reg0 to 0xf, other regs to 0 and finally refreshing NMT, PRG and CHR like I would during emulation.

the result is that at start I get bank 0 mapped in 0x8000-0xbfff and bank 0xf mapped in 0xc000-0xffff.

Most games work, but Snow Bros US and JP both refuse to start: they would need both regions to be set at bank 0, because they seem to only write registers to swith the lower bank once emulation is started and they require (at least in MESS) bank 0 in 0xc000-0xffff...

On the other hand, I have games which require high 16k bank to be initialized to 0xf (e.g. Rescue The Embassy Mission also only switches the lower bank but needs to start wit 0xf in the higher bank to work)

As a result, I am really puzzled!!

Where would you look for a bug? could a timing bug cause MMC1 to write in the wrong reg (or the wrong bankswitch value)?

Any other suggestion I might try?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

What value of reg0 does Snow Bros. use?
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Post by doppelganger »

If I remember correctly, MMC1 has no original power-up state and therefore reset code and interrupt vectors must be put into every PRG bank to accommodate for this random behavior. (edit: this seems to be true mainly for the original MMC1, revisions may exhibit slightly different power-up state behavior)

I stepped through Snow Bros at the beginning. Apparently it performs either an INC $FFFF or an INC $FFF9. The value in these locations is either $C0 (the first eight banks), $FF (the seven after that), and $FE (the last one).

As many nesdevvers know, writing a value of 1 to d7 of any MMC1 register causes the load register value at $8000-$9FFF to be ORed with $0C...this causes the PRG bankswitching mode to be set to 16k, and locks the upper bank at $C000-$FFFF to the last bank. This behavior occurs on the very first write of 1 to d7.

Now, obviously, when the values $C0 and FE are INCed and written to the MMC1, d7 will be set, causing this reset behavior.

It will seem intuitive that, if the value $FF is the one INCed, the value $00 will be written to MMC1 causing no reset behavior. And while it *is* true that this value is written, it is only the second of *two* writes the 6502 does on read-modify-write instructions. A properly emulated 6502, if executing INC $FFF9 where $FFF9 = $FF will do the following on each cycle:

Code: Select all

cycle  operation
----------------
1      fetch the opcode ($EE which is INC absolute)
2      fetch operand address low ($F9)
3      fetch operand address high ($FF)
4      read from operand address ($FFF9 gives $FF)
5      write pre-operation result ($FF is written, thus
       causing MMC1 reset) and perform operation
6      write post-operation result ($00 is written, possibly
       not acknowledged by MMC1, see note below)
Be sure you are emulating this behavior properly.

One additional thing: MMC1 may not acknowledge two writes so close together, in which case it will only acknowledge the first, pre-op write and ignore the second.
Last edited by doppelganger on Tue Jun 22, 2010 2:42 pm, edited 2 times in total.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

And now I finally understand why cc65's NES link script has a 12-byte VECTORS segment starting at $FFF4 instead of the 6 bytes at $FFFA that one might expect, so that the following code can be placed in all banks:

Code: Select all

.segment "VECTORS"
resetStub:
  inc $FFFC  ; location contains $F4, the low byte of resetStub's address
  jmp $C000  ; start of real reset code
  .addr nmiHandler, resetStub, irqHandler

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

Post by Bregalad »

I'm pretty sure MMC1A and MMC1B variants fixed that issue, OR-ing R0 with $0c at power-up somehow. I'm absolutely sure Final Fantasy II has only one reset vector in the last bank, and I did a bootleg of it using MMC1A, and it worked fine.

Has anyone actually tested a MMC1 that did't switch last PRG bank at $c000-$ffff on power up ?
Useless, lumbering half-wits don't scare us.
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

Pretty sure Memblers encountered the behavior.
etabeta
Posts: 109
Joined: Wed Nov 29, 2006 10:11 am
Location: Trieste, Italy

Post by etabeta »

thanks a lot guys for the answers (especially doppelganger for stepping through the code)

it seems I have to add Snow Bros to the list (already including AD&D Hillsfar and Bill & Ted) of games failing if MMC1 detects INC 0xffff... it seems I will need to fix this problem sooner than I hoped (MAME/MESS core is not super friendly if you need to track the # of cycles between accesses)
Post Reply