PDA

View Full Version : Development: I'm Fixin' It: Emerald's Broken PRNG


HackMew
May 1st, 2010, 6:35 AM
Brief Intro
As probably most of you are aware of already, Emerald has a faulty PRNG implementation. The game does not take care of reseeding during the startup, leading to the fact it can be easily abused to get perfect IVs and similar.

Description
While it can be useful, it's indeed a major glitch. Since the whole game randomness is affected, it definitely needs to be fixed. Taking a look at Ruby's code, I found out that the initial reseeding happens as soon as the game starts (i.e. when the boot screen shows up). R/S use their internal clook to generate a 16-bit seed. In Emerald, of course, this part is totally missing. So I decided to emulate the R/S approach by porting their reseeding routine to Emerald. Here's the outcome:

[css-div="font-family:consolas, courier new,monospace"].text
.align 2
.thumb
.thumb_func
.global EmeraldPrngFix

main:
push {lr}
ldr r1, .GET_CLOCK
bl bx_r1
lsr r1, r0, #0x10
lsl r0, r0, #0x10
lsr r0, r0, #0x10
eor r0, r1
ldr r1, .UPDATE_SEED
bl bx_r1
ldr r0, .UNK_RAM1
mov r4, #0x0
strb r4, [r0, #0x0]
pop {pc}

bx_r1:
bx r1

.align 2
.UNK_RAM1:
.word 0x03002700
.GET_CLOCK:
.word 0x0802F664|1
.UPDATE_SEED:
.word 0x0806F5F8|1[/css-div]

In order to apply the fix, assemble the routine and insert it somewhere where there's enough free space (if you never done it before, you better check my ASM tutorials). Take note of the address you used, and then replace 02 24 04 70 with FE 46 00 47, and 00 27 00 03 with XX XX XX XX, where XX XX XX XX represents the pointer to the routine's address + 1. For the respective offsets, see below.

The Offsets



Emerald US v1.0

[css-div="font-family:consolas,courier new,monospace"]0x402
0x478[/css-div]



This research document is Copyright © 2010 by HackMew.
You are not allowed to copy, modify or distribute it without permission.

ArmoredGuns
December 19th, 2011, 11:35 PM
Can someone please make an IPS patch of this fix? It seems pretty important, and it seems it requires more than just hex editing... I would love to have this fix but I'm no programmer :P

esperance
December 21st, 2011, 7:38 PM
Can someone please make an IPS patch of this fix? It seems pretty important, and it seems it requires more than just hex editing... I would love to have this fix but I'm no programmer :P

Okay, here you go... However, I really recommend you learn to apply simple hacks like this.
Download (http://www.mediafire.com/download.php?3dbj0obxb964309).
*Note: Routine inserted at 0x9C0D00*

Bond697
December 23rd, 2011, 12:19 AM
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:



ROM:08000560 @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560 @ void __fastcall seedRNG__()
ROM:08000560 seedRNG__:
ROM:08000560 10 B5 PUSH {R4,LR} @ this function never runs
ROM:08000562 06 48 LDR R0, =0x4000104 @ Timer1Data
ROM:08000564 04 88 LDRH R4, [R0]
ROM:08000566 20 1C MOVS R0, R4 @ Timer1Data to r0
ROM:08000568 6F F0 46 F8 BL setRNG__ @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49 LDR R1, =0x4000106 @ T1CNT
ROM:0800056E 00 20 MOVS R0, #0
ROM:08000570 08 80 STRH R0, [R1] @ turn off timer1
ROM:08000572 04 48 LDR R0, =0x2020000
ROM:08000574 04 80 STRH R4, [R0] @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC POP {R4}
ROM:08000578 01 BC POP {R0}
ROM:0800057A 00 47 BX R0
ROM:0800057A @ End of function seedRNG__
ROM:0800057A
ROM:0800057A @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C: .long 0x4000104 @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580: .long 0x4000106 @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584: .long 0x2020000 @ DATA XREF: seedRNG__+12r


ROM:0806F5F8 @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8 @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8 setRNG__: @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04 LSLS R0, R0, #0x10 @ dumb typecasting
ROM:0806F5FA 00 0C LSRS R0, R0, #0x10
ROM:0806F5FC 02 49 LDR R1, =0x3005D80 @ rng buffer
ROM:0806F5FE 08 60 STR R0, [R1] @ set rng to T1Dat
ROM:0806F600 02 49 LDR R1, =0x20249BC @ rng frame counter
ROM:0806F602 00 20 MOVS R0, #0 @ set counter to 0 to signify starting seed
ROM:0806F604 08 70 STRB R0, [R1]
ROM:0806F606 70 47 BX LR
ROM:0806F606 @ End of function setRNG__

ArmoredGuns
December 23rd, 2011, 1:42 AM
Okay, here you go... However, I really recommend you learn to apply simple hacks like this.

*Note: Routine inserted at 0x9C0D00*

Thank you very much!!! I greatly appreciate it :)

just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:



ROM:08000560 @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560 @ void __fastcall seedRNG__()
ROM:08000560 seedRNG__:
ROM:08000560 10 B5 PUSH {R4,LR} @ this function never runs
ROM:08000562 06 48 LDR R0, =0x4000104 @ Timer1Data
ROM:08000564 04 88 LDRH R4, [R0]
ROM:08000566 20 1C MOVS R0, R4 @ Timer1Data to r0
ROM:08000568 6F F0 46 F8 BL setRNG__ @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49 LDR R1, =0x4000106 @ T1CNT
ROM:0800056E 00 20 MOVS R0, #0
ROM:08000570 08 80 STRH R0, [R1] @ turn off timer1
ROM:08000572 04 48 LDR R0, =0x2020000
ROM:08000574 04 80 STRH R4, [R0] @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC POP {R4}
ROM:08000578 01 BC POP {R0}
ROM:0800057A 00 47 BX R0
ROM:0800057A @ End of function seedRNG__
ROM:0800057A
ROM:0800057A @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C: .long 0x4000104 @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580: .long 0x4000106 @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584: .long 0x2020000 @ DATA XREF: seedRNG__+12r


ROM:0806F5F8 @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8 @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8 setRNG__: @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04 LSLS R0, R0, #0x10 @ dumb typecasting
ROM:0806F5FA 00 0C LSRS R0, R0, #0x10
ROM:0806F5FC 02 49 LDR R1, =0x3005D80 @ rng buffer
ROM:0806F5FE 08 60 STR R0, [R1] @ set rng to T1Dat
ROM:0806F600 02 49 LDR R1, =0x20249BC @ rng frame counter
ROM:0806F602 00 20 MOVS R0, #0 @ set counter to 0 to signify starting seed
ROM:0806F604 08 70 STRB R0, [R1]
ROM:0806F606 70 47 BX LR
ROM:0806F606 @ End of function setRNG__


Hmm I wonder if FRLG's PRNG seeding routine is better than Ruby/sapphire's...

Kaphotics
January 28th, 2012, 8:52 AM
Hmm I wonder if FRLG's PRNG seeding routine is better than Ruby/sapphire's...

It's not, R/S was better due to the more variant initial starting seeds (hence more random).

FRLG had 0x0000 - 0xFFFF starting seeds, whereas R/S was 0x0 - 0x7FFFFFFF.

Both are definitely more random than Emerald, but R/S did it better. In later games (DPPt and BW) you have a mix of datetime and hardware timers (delay).

AlphaDrache
September 2nd, 2012, 7:23 AM
Are the addresses the same for the german emerald ROM?

Darthatron
September 2nd, 2012, 7:50 AM
Are the addresses the same for the german emerald ROM?

Probably, but to check just see if the bytes at the given offsets are the ones described in the tutorial.

Bond697
September 3rd, 2012, 12:52 PM
It's not, R/S was better due to the more variant initial starting seeds (hence more random).

FRLG had 0x0000 - 0xFFFF starting seeds, whereas R/S was 0x0 - 0x7FFFFFFF.

Both are definitely more random than Emerald, but R/S did it better. In later games (DPPt and BW) you have a mix of datetime and hardware timers (delay).

this is wrong. r/s seeds only go 0-0xffff also even though they use a more complex formula. the seeding is 16-bit either way, so no there's not more seeds.


ROM:080003E4 ; =============== S U B R O U T I N E =======================================
ROM:080003E4
ROM:080003E4
ROM:080003E4 seedRNG ; CODE XREF: main+30p
ROM:080003E4 PUSH {LR}
ROM:080003E6 BL buildSeed
ROM:080003EA MOVS R2, R0 ; s32 seed to r2
ROM:080003EC LSRS R0, R2, #0x10 ; r0 = seed >> 16
ROM:080003EE LDR R1, =0xFFFF
ROM:080003F0 ANDS R1, R2 ; r1 = seed & 0xFFFF (get lower 16 bits of seed)
ROM:080003F2 EORS R0, R1 ; upperSeed ^ lowerSeed
ROM:080003F4 BL setRNG
ROM:080003F8 POP {R0}
ROM:080003FA BX R0
ROM:080003FA ; End of function seedRNG
ROM:080003FA
ROM:080003FA ; ---------------------------------------------------------------------------
ROM:080003FC dword_80003FC DCD 0xFFFF ; DATA XREF: seedRNG+Ar


(sapphire)

aroenai
October 24th, 2012, 10:35 PM
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:



ROM:08000560 @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560 @ void __fastcall seedRNG__()
ROM:08000560 seedRNG__:
ROM:08000560 10 B5 PUSH {R4,LR} @ this function never runs
ROM:08000562 06 48 LDR R0, =0x4000104 @ Timer1Data
ROM:08000564 04 88 LDRH R4, [R0]
ROM:08000566 20 1C MOVS R0, R4 @ Timer1Data to r0
ROM:08000568 6F F0 46 F8 BL setRNG__ @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49 LDR R1, =0x4000106 @ T1CNT
ROM:0800056E 00 20 MOVS R0, #0
ROM:08000570 08 80 STRH R0, [R1] @ turn off timer1
ROM:08000572 04 48 LDR R0, =0x2020000
ROM:08000574 04 80 STRH R4, [R0] @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC POP {R4}
ROM:08000578 01 BC POP {R0}
ROM:0800057A 00 47 BX R0
ROM:0800057A @ End of function seedRNG__
ROM:0800057A
ROM:0800057A @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C: .long 0x4000104 @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580: .long 0x4000106 @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584: .long 0x2020000 @ DATA XREF: seedRNG__+12r


ROM:0806F5F8 @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8 @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8 setRNG__: @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04 LSLS R0, R0, #0x10 @ dumb typecasting
ROM:0806F5FA 00 0C LSRS R0, R0, #0x10
ROM:0806F5FC 02 49 LDR R1, =0x3005D80 @ rng buffer
ROM:0806F5FE 08 60 STR R0, [R1] @ set rng to T1Dat
ROM:0806F600 02 49 LDR R1, =0x20249BC @ rng frame counter
ROM:0806F602 00 20 MOVS R0, #0 @ set counter to 0 to signify starting seed
ROM:0806F604 08 70 STRB R0, [R1]
ROM:0806F606 70 47 BX LR
ROM:0806F606 @ End of function setRNG__


Can someone post an .ips patch that uses the built in code for Emerald, and possibly port it to R/S? The reason I ask is the batteries finally died in my copies of R/S/E so I wanted to start using my EZ Flash 3in1 and EZ Flash IV which both lack a RTC (gbata patched).

Edit: Oh wait, would that just be 61 05 00 08 at 0x478 for Emerald?
Edit 2: Nope white screen

ThomasWinwood
April 7th, 2014, 10:34 PM
Can someone post an .ips patch that uses the built in code for Emerald, and possibly port it to R/S?
This isn't an IPS patch (though making one is trivial) but I think that you can use the existing RNG seeding routine by making the following changes. (I would really appreciate someone checking that this does in fact seed the PRNG correctly - I'm on Linux, so the only debugging tools I have available to me are "does the ROM work" and "do I get anything odd, like a trainer ID of 00000".)


At 0x402 change 00 24 04 70 to FE 46 00 47.
At 0x478 change 00 27 00 03 to 61 05 00 08.
At 0x578 change 01 BC 00 47 to 00 BD 08 47.

MWisBest
March 22nd, 2017, 3:44 PM
This isn't an IPS patch (though making one is trivial) but I think that you can use the existing RNG seeding routine by making the following changes. (I would really appreciate someone checking that this does in fact seed the PRNG correctly - I'm on Linux, so the only debugging tools I have available to me are "does the ROM work" and "do I get anything odd, like a trainer ID of 00000".)


At 0x402 change 00 24 04 70 to FE 46 00 47.
At 0x478 change 00 27 00 03 to 61 05 00 08.
At 0x578 change 01 BC 00 47 to 00 BD 08 47.


Sorry to dig up an old thread, but unfortunately this does not work. As far as I can tell, the issue is timer1 isn't turned on, so the end result is the PRNG is (re)seeded to 0. It would be nice not to rely on the RTC for the seed, but I'm not particularly good at writing assembly, just interpreting it. :/

I see the link died for the IPS patch of HackMew's fix, so I've attached a new one that should be identical (routine still inserted at 0x9C0D00).

Edit: Actually I was able to whip something up to enable timer1 and then call the seed function, but the timer value is always the same since the timing is never different.
It turns out the PRNG is seeded with the built-in function when a new game is started, but not when an existing one is loaded. It turns on timer1 when New Game is pressed (or somewhere around there), and then after the player enters their name it calls the built-in seed-from-timer1 function at 0x560.

For this method to work, timer1 needs to be turned on when the opening movie begins playing, and the built-in seed-from-timer1 function needs to be called when "Continue" (Load Game) is pressed. How exactly that can be done, I'm not sure yet.


Edit2: Well I've surprised myself. I seem to have gotten this built-in timer-based PRNG seeding working.

There's 1 routine required. The byte edit at 0x400 uses the game's built in function for enabling T1, and the added routine is to run the seed function after the "Press Start" screen.

.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerPrngSeedAtMenu

main:
push {lr}
ldr r1, .SEED_RNG_FROM_T1
bl bx_r1
movs r0, #0
ldr r1, .MENU_CB_THING
bl bx_r1
pop {r0}
bx r0

bx_r1:
bx r1

.align 2
.SEED_RNG_FROM_T1:
.word 0x08000560|1
.MENU_CB_THING:
.word 0x0802F6F4|1


Compile and insert into free space. Byte changes required:

At 0x400 change 1D 48 00 24 04 70 to 00 F0 A8 F8 C0 46.
At 0xAAED0 change DD F6 02 08 to XX XX XX 08, where XX XX XX is the location of the routine (EmeraldTimerPrngSeedAtMenu) +1 (e.x. if you insert it at 0x9C0D00, you'd put 01 0D 9C 08).


I've also attached an IPS of this for those who would prefer that; the routine was inserted at 0x9C0D00.

DizzyEgg
March 23rd, 2017, 2:31 PM
.

Why not use the RTC?

MWisBest
March 23rd, 2017, 7:09 PM
Why not use the RTC?

Well that's not the method the game intended to be used. There's clearly a reason they changed to the timer method in FR/LG rather than using the RTC method from R/S; Emerald was released after FR/LG and has this timer method built-in, they just forgot to run it on each reset.


Oh, and if anybody is interested, here's a version that seeds the RNG with a full 32-bit value (0x0 to 0xFFFFFFFF instead of 0x0 to 0xFFFF). Requires 2 routines this time.

Byte edits required:

At 0x402 change 00 24 04 70 to FE 46 00 47.
At 0x478 change 00 27 00 03 to XX XX XX 08, where XX XX XX is the location of the first routine (TimersEnable) +1 (e.x. if you insert it at 0x9C0D00, you'd put 01 0D 9C 08).
At 0xAAED0 change DD F6 02 08 to XX XX XX 08, where XX XX XX is the location of the second routine (EmeraldTimerPrngSeedAtMenu) +1 (see above).


There's an IPS patch attached too.

.text
.align 2
.thumb
.thumb_func
.global TimersEnable

main:
push {lr}
mov r0, #0x80
ldr r1, .TM1CNT
strh r0, [r1]
mov r0, #0x84 @ set timer2 to increment when timer1 overflows ("count-up timing")
ldr r1, .TM2CNT
strh r0, [r1]
pop {pc}

.align 2
.TM1CNT:
.word 0x04000106
.TM2CNT:
.word 0x0400010A


.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerPrngSeedAtMenu

main:
push {lr}

@ disable the timers immediately so the values remain static
mov r0, #0x00
ldr r1, .TM1CNT
strh r0, [r1]
ldr r1, .TM2CNT
strh r0, [r1]

@ manually store the values into the rng and init values, half-word at a time
ldr r0, .TM1D
ldrh r0, [r0]
ldr r1, .RNG_STATE_PART_1
strh r0, [r1]
ldr r1, .TIMER_RESULT_PART_1
strh r0, [r1]

ldr r0, .TM2D
ldrh r0, [r0]
ldr r1, .RNG_STATE_PART_2
strh r0, [r1]
ldr r1, .TIMER_RESULT_PART_2
strh r0, [r1]

@ reset rng frame counter to 0
@ NOTE: the built-in rng seed function seems to think
@ this value is at 0x020249BC, whereas the rng
@ advancement routine says it's at 0x020249C0. lolwut
mov r0, #0
ldr r1, .RNG_FRAME_COUNTER
strb r0, [r1]

@ mov r0, #0 is required here as part of the routine this replaces,
@ but it's already done above here now; just noted in case it's changed.
ldr r1, .MENU_CB_THING
bl bx_r1
pop {r0}
bx r0

bx_r1:
bx r1

.align 2
.TM1D:
.word 0x04000104
.TM1CNT:
.word 0x04000106
.TM2D:
.word 0x04000108
.TM2CNT:
.word 0x0400010A
.RNG_STATE_PART_1:
.word 0x03005D80
.RNG_STATE_PART_2:
.word 0x03005D82
.RNG_FRAME_COUNTER:
.word 0x020249C0
.TIMER_RESULT_PART_1:
.word 0x02020000
.TIMER_RESULT_PART_2:
.word 0x02020002
.MENU_CB_THING:
.word 0x0802F6F4|1


EDIT: Optimized the original routines I posted and fixed a small bug. Size cut in half! :)

.text
.align 2
.thumb
.thumb_func
.global TimersEnable

main:
push {lr}
ldr r1, .TIMER_REGISTER_BASE
mov r0, #0x80
strh r0, [r1, #0x06] @ TM1CNT
mov r0, #0x84 @ set timer2 to increment when timer1 overflows ("count-up timing")
strh r0, [r1, #0x0A] @ TM2CNT
pop {pc}

.align 2
.TIMER_REGISTER_BASE:
.word 0x04000100


.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerPrngSeedAtMenu

main:
push {lr}

@ disable the timers immediately so the values remain static
mov r0, #0x00
ldr r1, .TIMER_REGISTER_BASE
strh r0, [r1, #0x06] @ TM1CNT
strh r0, [r1, #0x0A] @ TM2CNT

@ manually store seed into the rng state and init values because
@ the built-in seed function does not read a full 32-bits
ldrh r0, [r1, #0x04] @ TM1D
ldrh r1, [r1, #0x08] @ TM2D
lsl r1, #16 @ shift TM2D to be the upper 16-bits of the seed
orr r0, r1 @ combine TM1D and the shifted TM2D into a full 32-bits
ldr r1, .RNG_STATE
str r0, [r1]
ldr r1, .TIMER_RESULT
str r0, [r1]

@@ OPTIONAL: reset rng frame counter to 0
@@ This value isn't ever read by the game, so it's not really
@@ necessary to reset it unless you know what you're doing.
@@ NOTE: the built-in rng seed function seems to think
@@ this value is at 0x020249BC, whereas the rng
@@ advancement routine says it's at 0x020249C0. lolwut
@ mov r0, #0
@ ldr r1, .RNG_FRAME_COUNTER
@ str r0, [r1]

@ if "mov r0, #0" is uncommented above here, comment the one below
mov r0, #0
ldr r1, .MENU_INIT_CB
bl x_r1
pop {r0}
bx r0

x_r1:
bx r1

.align 2
.TIMER_REGISTER_BASE:
.word 0x04000100
.RNG_STATE:
.word 0x03005D80
@@.RNG_FRAME_COUNTER:
@@ .word 0x020249C0
.TIMER_RESULT:
.word 0x02020000
.MENU_INIT_CB:
.word 0x0802F6F4|1

MWisBest
March 29th, 2017, 6:47 AM
One last option I whipped up: another 32-bit seed, bottom 16-bits is timer-based, but the upper 16-bits is RTC based like HackMew's original fix.

Byte edits required:

At 0x400 change 1D 48 00 24 04 70 to 00 F0 A8 F8 C0 46.
At 0xAAED0 change DD F6 02 08 to XX XX XX 08, where XX XX XX is the location of the routine (EmeraldTimerPrngSeedAtMenu) +1 (e.x. if you insert it at 0x9C0D00, you'd put 01 0D 9C 08).


.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerAndRTCPrngSeedAtMenu

main:
push {lr}

@ disable the timer immediately so the value remains static
mov r0, #0x00
ldr r1, .TIMER_REGISTER_BASE
strh r0, [r1, #0x06] @ TM1CNT

@ get the "RTC seed" into r1
ldr r1, .GET_RTC_MINUTES
bl x_r1
lsr r1, r0, #16
@ no need to chop off the upper 16-bits of r0 like the original, it's done for us later
eor r1, r0

@ get the "timer seed" into r0
ldr r0, .TIMER_REGISTER_BASE
ldrh r0, [r0, #0x04] @ TM1D

@ make full seed in r0 (RTC seed as upper 16-bits)
lsl r1, #16
orr r0, r1

@ manually store seed into the rng state and init values because
@ the built-in seed function does not read a full 32-bits
ldr r1, .RNG_STATE
str r0, [r1]
ldr r1, .TIMER_RESULT
str r0, [r1]

@@ OPTIONAL: reset rng frame counter to 0
@@ This value isn't ever read by the game, so it's not really
@@ necessary to reset it unless you know what you're doing.
@@ NOTE: the built-in rng seed function seems to think
@@ this value is at 0x020249BC, whereas the rng
@@ advancement routine says it's at 0x020249C0. lolwut
@ mov r0, #0
@ ldr r1, .RNG_FRAME_COUNTER
@ str r0, [r1]

@ if "mov r0, #0" is uncommented above here, comment the one below
mov r0, #0
ldr r1, .MENU_INIT_CB
bl x_r1
pop {r0}
bx r0

x_r1:
bx r1

.align 2
.TIMER_REGISTER_BASE:
.word 0x04000100
.RNG_STATE:
.word 0x03005D80
@@.RNG_FRAME_COUNTER:
@@ .word 0x020249C0
.TIMER_RESULT:
.word 0x02020000
.GET_RTC_MINUTES:
.word 0x0802F664|1
.MENU_INIT_CB:
.word 0x0802F6F4|1