MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

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
The_YongGrand
Posts: 27
Joined: Tue Mar 19, 2013 9:30 am

MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by The_YongGrand » Sat Nov 21, 2020 10:51 pm

Hello there,

Recently I'm trying to understand how this MMC3 works, so I wrote up a short code based from the examples provided (Nerdy Nights) and then run it on the emulator (Nintendulator and FCEUX).

On the program:

1.) Assume that PRG 16KB block is one:

Code: Select all

  .inesprg 2   ; 1x 16KB PRG code
  .ineschr 0   ; 1x  8KB CHR data
  .inesmap 4   ; mapper 0 = NROM, no bank swapping
  .inesmir 0   ; background mirroring
2.) Bank 3 has the reset vector that goes to 0x8000:

Code: Select all

;;;;;;;;;;;;;;  

   .bank 3
  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
3.) Bank 1 has another short example program:

Code: Select all

;;;;;;;;;;;;;;
    .bank 1
    .org $8000
f1:	
    LDA #$01
    LDA #$02
HERE:
    JMP HERE
4.) and finally, Bank 0 has the main part of the program such as setup:

Code: Select all

  .bank 0
  .org $8000 
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40
  STX $4017    ; disable APU frame IRQ
  
  LDA #%00000110
  STA $8000
  LDA #$01
  STA $8001
  JMP f1    
  
;Forever:
;  JMP Forever     ;jump back to Forever, infinite loop
  
NMI:
  RTI
What I wanted this program to actually goes to the Bank 1's 0x8000, but on the emulator it ends up going to Bank 1's 0x8011 instead.

Is there a way I need to make it directly jump to Bank 1's 0x8000 from Bank 0? It looks like right after a bank-switch, it continues where the PC left off.

User avatar
olddb
Posts: 127
Joined: Thu Oct 26, 2017 12:29 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by olddb » Sat Nov 21, 2020 11:19 pm

You need your bank switching code somewhere in the $c000 fixed bank.
Once the bank is switched you can jump to the 8000-$9FFF area.

Also, does MMC3 guarantee bank0 at $8000 on startup?

EDIT:

Maybe this will help.

Code: Select all

  LDA #%00000110
  STA $8000
  LDA #$01
  STA $8001
  ;you are no longer on this bank, "JMP f1" can't be called
  JMP f1  
These comments are misleading.

Code: Select all

.inesprg 2   ; 1x 16KB PRG code
.ineschr 0   ; 1x  8KB CHR data
.inesmap 4   ; mapper 0 = NROM, no bank swapping
.inesmir 0   ; background mirroring
Last edited by olddb on Sun Nov 22, 2020 12:52 am, edited 4 times in total.
...

lidnariq
Posts: 9848
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by lidnariq » Sat Nov 21, 2020 11:42 pm

olddb wrote:
Sat Nov 21, 2020 11:19 pm
Also, does MMC3 guarantee bank0 at $8000 on startup?
No: you must put your reset vector in the fixed bank.

User avatar
olddb
Posts: 127
Joined: Thu Oct 26, 2017 12:29 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by olddb » Sun Nov 22, 2020 12:00 am

...
...

User avatar
Quietust
Posts: 1634
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by Quietust » Sun Nov 22, 2020 6:25 am

olddb wrote:
Sat Nov 21, 2020 11:19 pm
You need your bank switching code somewhere in the $c000 fixed bank.
Not even $C000-$DFFF is fixed on the MMC3, because a single write to $8000 can make it selectable (and make $8000-$9FFF fixed).
If you want to be safe, your reset vector must point to a location within $E000-$FFFF.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

The_YongGrand
Posts: 27
Joined: Tue Mar 19, 2013 9:30 am

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by The_YongGrand » Sun Nov 22, 2020 7:30 am

Hello,

I've just fixed that comment over there - should be 2x 16KB PRG code. And also re-arranging the code.

Code: Select all

  .inesprg 2   ; 2x 16KB PRG code
  .ineschr 0   ; 0x  8KB CHR data
  .inesmap 4   ; mapper 0 = NROM, no bank swapping
  .inesmir 0   ; background mirroring
  

   
;;;;;;;;;;;;;;;
    
  .bank 0
  .org $8000 

Forever:
  JMP Forever     ;jump back to Forever, infinite loop
  

;;;;;;;;;;;;;;

  .bank 1
  .org $A000
  LDA #$01
  LDA #$02
HERE:
   JMP HERE    
  
;;;;;;;;;;;;;;

  .bank 2
  .org $C000
RESET:
 SEI          ; disable IRQs
 CLD          ; disable decimal mode
 LDX #$40
 STX $4017    ; disable APU frame IRQ
  
BANKSW: 
  LDA #%00000110
  STA $8000
  LDA #$01 ; jump to 0xA000 or jump to 0x1A000?
  STA $8001   

NMI:
  RTI
  
;;;;;;;;;;;;;;  

   .bank 3
  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
  
I just moved the init code back to 0xC000 as start, it now jumps to 0xC000 normally on boot, but now that Bank-switch inside that area doesn't do any jumping anymore, skipped that thing to RTI and go nowhere else according to the debugger.

Is that Bank-Switch to "Bank 1" (lda #$01, sta $8001) means:
- switch to Bank 1 (second 8KB, 0xA000 to 0xBFFF) on the first physical 64K memory space (0x0000-0xffff) or
- switch to Bank 1 (second 8KB, 0xA000 to 0xBFFF) on the second physical 64K memory space (0x10000-0x1ffff) ?

User avatar
Quietust
Posts: 1634
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by Quietust » Sun Nov 22, 2020 10:34 am

The_YongGrand wrote:
Sun Nov 22, 2020 7:30 am
Hello,

I've just fixed that comment over there - should be 2x 16KB PRG code. And also re-arranging the code.

Code: Select all

...
  LDA #%00000110
  STA $8000
  LDA #$01 ; jump to 0xA000 or jump to 0x1A000?
  STA $8001   
...
I just moved the init code back to 0xC000 as start, it now jumps to 0xC000 normally on boot, but now that Bank-switch inside that area doesn't do any jumping anymore, skipped that thing to RTI and go nowhere else according to the debugger.

Is that Bank-Switch to "Bank 1" (lda #$01, sta $8001) means:
- switch to Bank 1 (second 8KB, 0xA000 to 0xBFFF) on the first physical 64K memory space (0x0000-0xffff) or
- switch to Bank 1 (second 8KB, 0xA000 to 0xBFFF) on the second physical 64K memory space (0x10000-0x1ffff) ?
The answer here is neither - since you wrote #$06 (#%00000110) to $8000, writing #$01 to $8001 will map the 2nd 8KB PRG ROM bank (technically, the address range $002000-$003FFF within the ROM chip itself) to $8000-$9FFF within the CPU's address space.

Also, as I noted above, your RESET and bank-switching code really should be in bank 3 in this particular program, because if you happened to write #%x1xxxxxx (e.g. #$46) to $8000, then $C000-$DFFF would be replaced with the first swappable bank (i.e. what would be selected if you then wrote to $8001) and $8000-$9FFF would switch to being hardwired to the 2nd-last bank.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

User avatar
olddb
Posts: 127
Joined: Thu Oct 26, 2017 12:29 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by olddb » Sun Nov 22, 2020 2:43 pm

Haven't tested this, but try:

Code: Select all

  .inesprg 2   ; 2x 16KB PRG code
  .ineschr 0   ; 0x  8KB CHR data
  .inesmap 4   ; mapper 0 = NROM, no bank swapping
  .inesmir 0   ; background mirroring
  

;;;;;;;;;;;;;;;
    
  .bank 0
  .org $8000 

start0:
Forever:
  JMP Forever     ;jump back to Forever, infinite loop
  

;;;;;;;;;;;;;;

  .bank 1
  .org $8000
start1:
  LDA #$01
  LDA #$02
HERE:
   JMP HERE    
  
;;;;;;;;;;;;;;

  .bank 2
  .org $8000
start2:
  jmp start2
;;;;;;;;;;;;;;  

 .bank 3
 .org $e000
 RESET:
 SEI          ; disable IRQs
 CLD          ; disable decimal mode
 LDX #$40
 STX $4017    ; disable APU frame IRQ
  
BANKSW: 
  LDA #%00000110
  STA $8000
  LDA #$01 
  STA $8001   
  ;now cpu "window $8000-$9fff" holds rom section $2000-$3fff (bank1).
  ;it's "safe" to jump to label "start1"
  jmp start1
  
  ;if you wanted to jump to label "start0"
  LDA #%00000110
  STA $8000
  LDA #$00 ; <- change here 
  STA $8001   
  ;now cpu "window $8000-$9fff" holds rom section $0000-$1fff (bank0). 
  ;it's "safe" to jump to label "start0"
  jmp start0
  
NMI:
  RTI
   
   
  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
 
Last edited by olddb on Sun Nov 22, 2020 3:43 pm, edited 1 time in total.
...

User avatar
Quietust
Posts: 1634
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by Quietust » Sun Nov 22, 2020 3:27 pm

That's close, but not quite right - there are only two "windows" that can hold any bank, along with one "window" that always points at "section 6" (and the window at $E000-$FFFF that always points at "section 7").

The trick is that those windows can "change place" depending on the last value you wrote to the register at $8000 - if bit 6 is clear, then $8000-$9FFF is the first window and $C000-$DFFF is fixed at section 6, but if bit 6 is set, then $C000-$DFFF is the first window and $8000-$9FFF is fixed at section 6.

This actually changes the instant you write to $8000, not when you write to $8001, so you can't just write $06->$8000 + $xx->$8001 followed by $46->$8000 + $xx -> $8001 to put custom banks at both $8000 and $C000 (like some older emulators will let you do).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

User avatar
olddb
Posts: 127
Joined: Thu Oct 26, 2017 12:29 pm
Contact:

Re: MMC3 bankswitching - need to switch back to 0x8000 after the bankswitch.

Post by olddb » Sun Nov 22, 2020 3:45 pm

I see. Took out link.
...

Post Reply