This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

MMC3 write protection

MMC3 write protection
by on (#118654)
MMC3 is supposed to have a register at $A001 that write-protects PRG RAM (WRAM) at $6000-$7FFF but still allows it to be read. According to the wiki, $00 is open bus, $80 is read/write, and $C0 is read-only. But I'm having trouble verifying that this protection is in place. Here's the code I tried:
Code:
MMC3_WRAM_ENABLE = $A001
MMC3_WRAM_OFF = $00
MMC3_WRAM_RW = $80
MMC3_WRAM_RO = $C0

.proc mmc3_test_wram_protection

  ; make sure writes at least take
  ldy #MMC3_WRAM_RW
  sty MMC3_WRAM_ENABLE
  ldx #$6B  ; the "bad" value
  lda #$B6  ; the "good" value
  sta $6000
  cmp $6000
  bne protproblem

  ; make sure writes don't take if set to read-only
  ldy #MMC3_WRAM_RO
  sty MMC3_WRAM_ENABLE
  stx $6000
  cmp $6000
  bne roproblem

  ; make sure it can't be read from open bus
  ldy #MMC3_WRAM_OFF
  sty MMC3_WRAM_ENABLE
  cmp $6000
  beq protproblem

  ; test for $6000/$E000 glitch (Crystalis map corruption bug)
  ldy #MMC3_WRAM_RW
  sty MMC3_WRAM_ENABLE
  stx MMC3_IRQ_DISABLE
  cmp $6000
  bne protproblem

  lda #0
  rts
protproblem:
  lda #MAPTEST_WRAMEN
  rts
roproblem:
  lda #MAPTEST_WRAMRO
  rts
.endproc

On both FCEUX 2.2.0 and my PowerPak, I get MAPTEST_WRAMRO returned instead of 0. I've stepped through this subroutine in FCEUX 2.2.0's debugger to make sure the problem happens in this subroutine, not some unrelated defect in the test harness. But if you want, I can give you a minimal buildable program that demonstrates this. At this point I want to know if the problem is in my emulator and flash device or all in my head.
Re: MMC3 write protection
by on (#118656)
FCEUX (as-of 2.2.1) completely ignores the RAM protection register. The only thing that it does on writes to $A001 is set a variable A001B, which in turn is only used in its mapper 49 code.
Re: MMC3 write protection
by on (#118657)
Apparently the Linux port of Nestopia has been fixed, and the test runs as expected.
Re: MMC3 write protection
by on (#118659)
Also verified on my Crystalis cart:
Code:
; When run with Crystalis cart:
; 00 60 61 12 34
; C0 12 34 12 34
; 80 56 78 56 78

.include "shell.inc"

MMC3_WRAM_ENABLE = $A001
MMC3_WRAM_OFF   = $00
MMC3_WRAM_RW    = $80
MMC3_WRAM_RO    = $C0

wram = $6000

main:
        lda #MMC3_WRAM_OFF
        jsr test_wram
       
        lda #MMC3_WRAM_RO
        jsr test_wram
       
        lda #MMC3_WRAM_RW
        jsr test_wram
       
        rts

test_wram:
        pha
        ; Set initial values
        mov MMC3_WRAM_ENABLE,#MMC3_WRAM_RW
        mov $6000,#$12
        mov $6100,#$34
        pla
       
        ; Change to mode being tested
        ; and try writing
        jsr print_a
        sta MMC3_WRAM_ENABLE
        mov $6000,#$56
        mov $6100,#$78
        jsr print_wram
       
        ; See what's in WRAM now
        mov MMC3_WRAM_ENABLE,#MMC3_WRAM_RW
        jsr print_wram
       
        jsr print_newline
        rts

print_wram:
        lda $6000
        jsr print_a
        lda $6100
        jsr print_a
        rts
Re: MMC3 write protection
by on (#118672)
The reason the write protection probably isn't implemented in many emulators is the fact that MMC6 also has overlapping write protection registers at the same address, but they behave differently than in MMC3. As we all know MMC3 and MMC6 share the same iNES mapper number. If the behavior of MMC3 is implemented, StarTropics will/may cease to work (this is why I didn't implement said bits in my PowerPak save state mappers).

See http://wiki.nesdev.com/w/index.php/MMC6
Re: MMC3 write protection
by on (#118676)
thefox wrote:
If the behavior of MMC3 is implemented, StarTropics will/may cease to work

The extant MMC6 games are StarTropics, StarTropics 2, and StarTropics 2 ("BLOCKS" version). These can be recognized by PRG hashes or by an NES 2.0 RAM size of 1024 bytes. But when I specify NES 2.0 RAM size of 8192 bytes, I expect MMC3 behavior.
Re: MMC3 write protection
by on (#118677)
And FCEUX still hasn't implemented diddly nor squat of NES2.0.
Re: MMC3 write protection
by on (#118756)
So I can accept that emulators that don't support NES 2.0 are likely to lack support for MMC3 read-only mode in order to get the MMC6 games working. This made me wonder what other MMC3-class mappers have unimplemented WRAM features on popular emulators. So I decided to implement the corresponding test for the FME-7. As I understand it, here's how it's supposed to work:
Code:
76543210  Reg 8: Bank at $6000-$7FFF
EE.BBBBB
|| +++++- Select 8K bank at $6000-$7FFF
++------- 0: ROM; 3: RAM; something else: open bus

But Nestopia 1.45, FCEUX 2.2.0, James Holodnak's nesemu2 0.6.1, and the PowerPak all appear to keep ROM banked in when the register is set to open bus. I call this subroutine and instead of getting 0, I get MAPTEST_WRAMEN.
Code:
FME7_SELECT = $8000
FME7_DATA = $A000
FME7_PRGBANK  = 8
FME7_PRGBANK_ROM = $00  ; these are OR'd with the bank number
FME7_PRGBANK_OFF = $40  ; but only in FME7_PRGBANK+0
FME7_PRGBANK_RAM = $C0

; CONSTANT_01 is a ROM address in $E000-$FFFF that contains $01.
; This is its location mirrored into the $6000 window.
WRAM_LOC = CONSTANT_01 - $8000

.proc fme7_test_wram_protection
  lda has_wram
  beq skip_test

  ; Write to last bank of RAM
  lda #FME7_PRGBANK+0
  sta FME7_SELECT
  lda #FME7_PRGBANK_RAM|$3F
  sta FME7_DATA
  lda #2
  sta WRAM_LOC
  cmp WRAM_LOC
  bne protproblem2

  ; Read last bank of ROM
  lda #FME7_PRGBANK_ROM|$3F
  sta FME7_DATA
  lda WRAM_LOC
  cmp CONSTANT_01
  bne roproblem

  ; Read open bus
  lda #FME7_PRGBANK_OFF|$3F
  sta FME7_DATA
  lda WRAM_LOC  ; open_bus should be $7F
  cmp #3        ; 0: most ROM banks; 1: last ROM bank; 2: last RAM bank
  bcc protproblem

skip_test:
  lda #0
have_result:
  ldy #FME7_PRGBANK_RAM|$3F
  sty FME7_DATA
  rts
protproblem:
  lda #MAPTEST_WRAMEN
  bne have_result
roproblem:
  lda #MAPTEST_WRAMRO
  bne have_result
protproblem2:
  lda #MAPTEST_WRAMEN2
  bne have_result
.endproc


An aside: PowerPak appears to implement the proposal for large PRG RAM on FME-7. I was surprised when my other test program found four banks of usable PRG RAM instead of just one.


EDIT 1: I had l_oliveira test on a modded Sunsoft cart. It appears I had a mistaken value for FME7_PRGBANK_OFF. It might need to be $40, not $80. Let me try again.

EDIT 2: That was in fact the problem. I have corrected the code above.