My first light only shines at a small part of the ROM. I found the random number generator, but I know almost nothing else about Mario Paint. I have no way to change the palette, replace the stamps, augment the coloring book, or add background music, because I never found those things in the ROM.
I am not the first hacker to shine light at Mario Paint. I can guess that the trade secrets of Nintendo include the original source code of Mario Paint; but I can also guess that hackers without connection to Nintendo, studied and hacked Mario Paint around 1993..1994. I have rumour that these hackers made hack such that Mario Paint uses SNES controller instead of SNES mouse, so to play Mario Paint at a SNES without a mouse. I have not acquired this hack.
My own light found the random number generator, because I started at reset. When you power on or reset any SNES game, the 5A22 central processor executes the RESET handler before it executes any other code. I now show my disassembly of the beginning of the RESET handler. (The copyright of all code in my disassembly belongs to Nintendo. I only quote small amounts of code.)
;;; RESET handler for 6502 emulation mode at_reset: /*008000 78*/ sei /*008001 18*/ clc /*008002 fb*/ xce /*008003 c2 20*/ rep #PM /*008005 a9 00 00*/ lda #$0000 /*008008 8f e2 04 00*/ sta.l $0004e2 /*00800c a9 00 00*/ lda #$0000 /*00800f 8f 08 00 00*/ sta.l $000008 /*008013 e2 20*/ sep #PM /*008015 9c 00 42*/ stz.w $4200 /*008018 9c 0b 42*/ stz.w $420b /*00801b 9c 0c 42*/ stz.w $420c /*00801e a9 80*/ lda #$80 /*008020 8d 00 21*/ sta.w $2100 /*008023 9c 33 21*/ stz.w $2133 /*008026 9c 16 40*/ stz.w $4016 /*008029 c2 30*/ rep #PM | PX /*00802b a2 ff 1f*/ ldx #$1fff /*00802e 9a*/ txs ; stack: $????..$1fff /*00802f a0 00 00*/ ldy #$0000 /*008032 5a*/ phy /*008033 2b*/ pld ; direct page: $0000..$00ff /*008034 ca*/ dex ;; Enter this loop with a = $0080, x = $1ffe. ;; Read RAM $0001..$1fff to compute strange 16-bit sum. /*008035 75 00*/ adc $00,x ; read 2 bytes, add to sum /*008037 ca*/ dex ; x - 1 => x /*008038 d0 fb*/ bne -5 /*$8035*/ ; loop until x == $0000 /*00803a 85 02*/ sta $02 ; store strange 16-bit sum
The assembly code seems to compute the sum of the bytes at RAM $0001 through RAM $1ffe, plus 256 times the sum of the bytes at RAM $0002 through RAM $1fff, modulo 2**16. This sum is strange because of the repeated and overlapping usage of RAM $0002 through RAM $1ffe. The strange sum is equal to value modulo 2**16 of the byte at RAM $0001, plus 256 times the byte at RAM $1fff, plus 257 times the sum of the bytes at RAM $0002 through RAM $1fff. This multiplication by 256 or 257 seems to lack purpose. So the formula seems strange, random and useless.
Also, Mario Paint never initializes most of those RAM bytes. The game writes zero to RAM addresses $0008, $0009, $04e2, $04e3, $1ffe and $1fff, before computing the strange sum. All other RAM addresses have uninitialized values leftover from power on or reset. So the input to the formula seems strange, random and useless.
When I encountered the strange, random formula with the strange, random input, I suspected that I misinterpreted the disassembly. I believed that a strange sum of uninitialized RAM had no purpose. I tried to find a better interpretation, where the formula would have a purpose, and the input would come from initialized RAM, but I failed. I later noticed that a strange sum of uninitialized RAM might provide the entropy to seed a random number generator.
So I searched the Mario Paint ROM for something that uses the strange sum to seed a random number generator. Mario Paint stores the sum at DP $02, so I searched for something that reads DP $02.
I found some code that passes the immediate value $02 to a subroutine $01d308.
/*00805a a9 02*/ lda #$02 /*00805c 22 08 d3 01*/ jsl $01d308
The subroutine $01d308 never reads DP $02, so is the wrong place.
;;; jsl subroutine ;;; takes A = value to store to ring buffer ;;; preserves X, Y ;;; ;;; uses RAM $0004ec..$0004fb, a mysterious ring buffer ;;; RAM $00052c, barrier index ;;; RAM $000530, current index in ring buffer ;;; ;;; Pushes A to the ring buffer. This stores A to the ;;; ring buffer at the current index. Unless the next ;;; index equals the barrier index, then sets the ;;; current index to the next index. /*01d308 da*/ phx ; Push X, /*01d309 08*/ php ; processor flags. /*01d30a e2 30*/ sep #PM | PX /*01d30c 48*/ pha ; push parameter A /*01d30d af 30 05 00*/ lda.l $000530 /*01d311 aa*/ tax ; current index => X /*01d312 68*/ pla ; pull parameter A /*01d313 9f ec 04 00*/ sta.l $0004ec,x ; A => ring buffer /*01d317 e8*/ inx /*01d318 8a*/ txa /*01d319 29 0f*/ and #$0f ; (index + 1) mod 16 => A /*01d31b cf 2c 05 00*/ cmp.l $00052c ; If A == RAM $00052c /*01d31f f0 04*/ beq +4 /*$1d325*/ ; then do nothing, /*01d321 8f 30 05 00*/ sta.l $000530 ; else A => current index. /*01d325 28*/ plp /*01d326 fa*/ plx ; restore pf, X /*01d327 6b*/ rtl ; return from $01d308
I followed the RESET handler across a jump, and found some code that reads DP $02 before calling a subroutine $01e238.
/*008554 a5 02*/ lda $02 ; (unnecessary, see $01e238) /*008556 22 38 e2 01*/ jsl $01e238
This lda $02 in the ROM is unnecessary, because the subroutine $01e238 does lda $02 near the start of the subroutine. This lda $02 is only my hint that the subroutine $01e238 seeds the random number generator.
So I studied the subroutine $01e238 and the related subroutines. I learned how Mario Paint uses the strange sum as entropy to seed the random number generator. I learned how to call subroutine $01e20c to generate a random number. I added the addresses to Mario Paint/address map, and I created the wiki page for Mario Paint/random number generator.
I also wrote a patch for Mario Paint to cause all random numbers to be zero.
;;; mario-paint.i .memorymap defaultslot 0 slot 0 start $8000 size $8000 .endme .rombanksize $8000 .rombanks 32 .background "../mario-paint.sfc"
;;; mp-no-random.s .include "mario-paint.i" ;;; Cause jsl $01e20c to return a constant value, ;;; not a random value. .bank $01 .orga $e20c .section "patch" overwrite php rep #$20 ; 16-bit A lda #0 plp rtl .ends
I used my patch to observe various things in Mario Paint that use random numbers.