MMC1 boot code questions...

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

3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

MMC1 boot code questions...

Post by 3gengames »

Well, the main question I have right now, is this okay to boot safely into a program from MMC1 to all situations? And DMC fires IRQ's, correct? FCEUX doesn't boot into multiple banks, but this is correct way to do it right amd should work? In A I return the bank number because this is going to be a bank test for an MMC1 cart later. [hopefully today] It's taken me a little to write this because going all out to get a program into X bytes is something I'm not used to yet. :) Thanks!

Also, just making sure, the fixed bank is always the last bank on the chip, correct?

Code: Select all

  .bank 31
  .org $FFF0
  .db $00
MMC1GlitchBoot31:
  SEI
  LDA #$9F
RTIBank31:
  STA $8040
  JMP [$FFFC]
  .dw RTIBank31+1 ;NMI
  .dw MMC1GlitchBoot31 ;Reset
  .dw RTIBank31+1 ;IRQ
Also, each bank is 8KB and we're going to use a 256K ROM for this. FFF0 is 0 in all banks, nothing useful can be used for it really.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Writing any value from $80 through $FF to any address from $8000 through $FFFF will reset the MMC1. This changes the PRG mode to fixed last bank in $C000 and resets the 5-bit shift register.

It shouldn't be JMP [$FFFC]; it should be JMP to the real entry point of your program. Otherwise, you'll end up in an infinite loop executing MMC1GlitchBoot31 over and over again because $FFFC still points at MMC1GlitchBoot31.

It's also wise to have these vectors at the end of each 16 KiB bank of the program, just in case you get reset while using 32 KiB mode or fixed-$8000 mode, or just in case you end up running on an MMC1 revision with poorly defined initial PRG bank values. See my SGROM/SNROM template for how to get ca65 to do this. I haven't used NESASM, but I think you'll probably have to repeat that code in every odd numbered half-bank (1, 3, 5, 7, ... 31).

DMC has three actions it can apply at the end of the waveform: stop ($00), repeat ($40), or stop and IRQ ($80). In stop and IRQ mode, the DMC will fire an interrupt eight samples (one byte) before playback ends, giving you a few hundred CPU cycles to set up the next sample for gapless playback. It won't trigger any IRQs unless you CLI (set minimum interrupt priority to 0) and actually put DMC in stop and IRQ mode, but I still wouldn't recommend handling NMI and IRQ from the same routine.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

31 is the last bank, and yeah before you replied I changed it to an actual entry point for that bank, and it seems to work in FCEUX. But FCEUX doesn't open in other emulators. And yeah, I guess it could be taken out, but 16 bytes is an okay header size for me, nice and "round, I think I'll just keep it in all banks *just in case* the MMC1 didn't take the read and then the boot code could run again if it fails.

Yep, the 9F in bank 0 is $80, $81 in bank 1, etc. And yeah, 8KB sized banks is something I didn't take account for, then that means not needing it in all banks, so that should be $8F in the last bank and I need to change my code later for that.


Also, not that I'm relying on it for something, but is the reset state of the CPU the same as the cold boot state? Or would A,X,Y just all be unchanged?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Only bit 0 ($01) and bit 7 ($80) of the value written to $8000-$FFFF are ever used. If bit 7 is true, all other bits are ignored. So $9F, $81, and $8F all have the same effect.

You say having the actual entry point in the JMP fails in other emulators. What does it do if you step through it in Nintendulator?
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

It's not that it fails, it's just there because if I have more code I can swap banks without changing headers and also because it just seemed right to keep something there, so even if it has an undesired effect for any reason, it'll still work. And yeah, I'm at home now, I'll try it on all other emulators now to see if one boots in any bank.

And yep, that's how I understood it. That's why my load number to write to the MMC1 is also doubling as my "booted in bank" numbers for the main routine.
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Post by doppelganger »

3gengames wrote:
Also, not that I'm relying on it for something, but is the reset state of the CPU the same as the cold boot state? Or would A,X,Y just all be unchanged?
The state of the CPU upon pressing the reset button, that is, the warm boot state, is whatever it was just before the reset line to the CPU went low. The registers A, X and Y are not affected by any of the interrupt lines or the reset line going low.

As far as A, X and Y being a known value in the warm boot state, that would depend on whether the CPU executes a JMP ($FFFC) or the reset line goes low. If a JMP ($FFFC) is performed, A X and Y could definitely contain a known value. A press of the reset button, however, could happen at any time, and with code executing incredibly fast by human standards (approximately 1,786,840 cycles in a second) the registers A X and Y will have to be taken as indeterminate.
Be whatever the situation demands.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

doppelganger wrote:A press of the reset button, however, could happen at any time
Unless you wrote a "please reset your console" message to the screen and entered a loop that doesn't alter the registers you'll want to check later, in order to tell if the player followed your instructions... =)
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

tokumaru wrote:Unless you wrote a "please reset your console" message to the screen and entered a loop that doesn't alter the registers you'll want to check later, in order to tell if the player followed your instructions... =)
Then your game wouldn't run properly on some emulators or console revisions. X-Men for Sega Genesis has exactly the situation you describe where the player needs to press Reset to continue. On a Nomad, the game is unplayable past that point.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

This isn't for anything like that, just trying [which has been done now and just needs a UI for my console] to record boot state, report to the user all info about the MMC1 boot, banks wired good, etc. I just got done with this program and it's pretty good. I'll post it later for people who want to test emulator parts with it when it's done. It's nothing big, I just kinda needed this for the project because never messing with MMC1, need to learn it inside and out, which has been done thanks to the info here. :)

And even if you had to reset to continue past something. Besides using a CPU location [Backup'd SRAM would be the logical place of choice, right?) if you did it just based on registers, then you *could* possibly reset at the perfect time and then have that cause them to skip past a majority of the game. I can assure you I'd never do this....that just....not well thought out, even though it'd probably never happen.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

tepples wrote:X-Men for Sega Genesis has exactly the situation you describe where the player needs to press Reset to continue.
Cool, I never though this had actually been done! And I used to think that the second X-Men game was unusual, for dropping you directly into an action stage with a random character before even showing any sort of title screen or menu.

As for detecting resets, Kirby's Adventure on the NES does it... Not for anything important I think, it just seems to skip the part that teaches how to draw Kirby.
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

Square seems to like detecting resets. In Final Fantasy games, they skip the story intro. In Rad Racer and 3D World Runner they also skip the title screen, and if you're in the ending you can press reset to watch the ending again !

They do that just by having some particular variable set to particular states, and they check those variables when booting. Note that those games does not clear the memory so this technique works.
Useless, lumbering half-wits don't scare us.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

Well, if anybody makes an MMC1 cart, this is what I was working on to learn how to use MMC1, my first mapper, and to test our cartridge we made. It works for now, but it's not final at all, I plan to add detection if SRAM is even there and then also condense it all into the last 16KB bank. It's no problem size-wise. I just have to put it together. Have fun. Source included and it's ready to compile, the rom is in program and all files should be self descriptive. Code will be comment with the later final versions.

http://www.2shared.com/file/EJYpZ4Tm/MM ... eader.html
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

I just ran that on the emulators NESICIDE and Nintendulator. It reports all banks bad except bank 0, and it boots in 0F so that's how it runs. Anybody know why it fails? Is it because of the indirect addressing to address the last write's location? This is the code it uses:

Code: Select all

BankswitchControl:
  LDY #$80
  STY ZeroWrite
  JMP MainBankSwitch
BankswitchCharacterLower:
  LDY #$A0
  STY ZeroWrite
  JMP MainBankSwitch
BankswitchCharacterUpper:
  LDY #$C0
  STY ZeroWrite
  JMP MainBankSwitch
BankswitchProgram:
  LDY #$E0
  STY ZeroWrite
MainBankSwitch:
  AND #$1F
  STA $8000
  LSR A
  STA $8000
  LSR A
  STA $8000
  LSR A
  STA $8000
  LSR A
  STA [Zero],Y
  RTS
Also it should be noted the program works fine on an MMC1B2 that I've tested on real hardware without any problems at all. Also, one day or not I will probably also edit it to only show SRAM stuff if it's detected. For now, if you have no SRAM, just don't mind it.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

I'd advise against using indirect or indexed addressing for writing to the MMC1 ports. Instead, I've seen most MMC1 games use separate subroutines that write to $8000, $A000, $C000, and $E000.

Are you using CHR ROM or CHR RAM?
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

CHR-RAM, 8KB.

And why would you advise against it? While I probably am going to separate them to write better equipped bank switching routines where it rewrites the least possible of the port, still, is there any reason for it to fail?
Post Reply