Of course, before you start, you need some debugger. If you were able to buy the no$gba - lucky for you. It seems like it can't be bought any more. That's why i use iDeas. It's slow and the debugger doesn't offer too many options, but at least it get's some jobs done.
Also, you need an image of a Pokemon game. To extract it from your Pokemon cartridge, you'll most
likely need a flash module to run the extraction software. If you have a slot2-based flash module,
you can start the extraction tool, then switch cartridges and extract the data to slot2. If you only
have a slot1-based flash module, you can transfer the data via wireless.
This takes a long time (can take an hour for a game), but still you end up with a working
copy of your own game.
No matter which way you have to use, "Rudolph" tends to be part of the name of the tool for it.
Searching with iDeas seems to be impossible, you'd rather like to use some hex editor for it.
If you do, you should note some mapping issues. Let's look at the PRNG for an example:
The PRNG starts at 0x0201B9EC when loaded. However, if you look at the file in the
hex editor, you will find the instructions at 0x0001F9EC. This means that some things are mapped
File.begin | File.end | mem.begin | mem.end | diff |
---|---|---|---|---|
0x00004000 | 0x0010AF9F | 0x02000000 | 0x02106F9F | +0x01FFC000 |
Also note, these offsets may and will differ when using different games, versions
and language versions.
I found 05 49 06 48 0A 68 13 1C 43 43 05 48 18 18 08 60
(which is the PRNG)
in english diamond: | 0x0001F9EC |
---|---|
in english pearl: | 0x0001F9EC |
in german Diamant: | 0x0001FA38 |
Routine | Begin | End | Input | Output |
---|---|---|---|---|
Mersenne Init (prev: unknown1) | 0x0201BA1C | 0x0201BA4D | R0: starting Seed M0 | no reg, plenty of mem |
MersenneInit.D | 0x0201BA50 | 0x0201BA53 | 0x021C4D48 = address of PRNG seed | |
MersenneInit.D | 0x0201BA54 | 0x0201BA57 | 0x02105BA8 = address | |
MersenneInit.D | 0x0201BA58 | 0x0201BA5B | 0x021C4D50 | |
MersenneInit.D | 0x0201BA5C | 0x0201BA5F | 0x6C078965 = Masuda Factor | |
Mersenne | 0x0201BA60? | 0x0201BB43 | none?? | R0: "random" number |
Mersenne.D | 0x0201BB44 | 0x0201BB47 | 0x02105BA8 - address of Mersenne index number | |
Mersenne.D | 0x0201BB48 | 0x0201BB4B | 0x00001571 - Used as seed for Mersenne-reinit? | |
Mersenne.D | 0x0201BB4C | 0x0201BB4F | 0x021C4D4C - address of mersenne table | |
Mersenne.D | 0x0201BB50 | 0x0201BB53 | 0x02105BAC | |
Mersenne.D | 0x0201BB54 | 0x0201BB57 | 0x7FFFFFFF | |
Mersenne.D | 0x0201BB6C | 0x0201BB6F | 0x9D2C5680 - used in Mersenne | |
???? | 0x02020C2C | ???? | This is called from PRNG | |
Pokeradar something | 0x0205DED4 | 0x0205DF43 | ??? | ??? |
Pokeradar try | 0x0205E30C | 0x0205E3EB | ??? | ??? |
Pokeradar (shiny patch check) | 0x0205E40C | 0x0205E475 | none | R0: 1 for shiny patch, 0 for regular |
Pokeradar.D | 0x0205E478 | 0x0205E47B | 0x00002008 | |
Pokeradar.D | 0x0205E47C | 0x0205E47F | 0x0000FFFF | |
PID Generation (wild) | 0x02066D90 | ??? | R4: wanted nature | Stack: PID |
Check PID vs SIDTID for shinyness | 0x02068AAC | 0x02068AD3 | R0: SIDTID
R1: PID |
R0: 1 if PID is shiny, 0 if not |
ShinynessCheck.D | 0x02068AD4 | 0x02068AD7 | 0xffff0000 | |
Division | 0x020EBC80 | ??? | R0: dividend
R1: divisor |
R0: quotient R0/R1
R1: remainder R0%R1 |
Unknown1.D | 0x02105BA8 | 0x02105BAB | MersenneInit stores here (index for Mersenne?) | |
PRNG.D | 0x021C4D48 | 0x021C4D4B | Current Seed for PRNG | |
Mersenne.D | 0x021C4D4C | 0x021C4D4F | Seems to be (initial) Mersenne Table (m0) | |
Mersenne.D | 0x021C4D50 | 0x021C570F | Seems to be (initial) Mersenne Table (624 entrys, each 4 byte) | |
Starter.D | 0x021D9068 | 0x021D906B | 0x00000183 = Starter #1 (when selecting starter) | |
Starter.D | 0x021D906C | 0x021D906F | 0x00000186 = Starter #2 (when selecting starter) | |
Starter.D | 0x021D9070 | 0x021D9073 | 0x00000189 = Starter #3 (when selecting starter) | |
somewhere in Masuda Loop | 0x021ED046: call Masuda cycle
0x021ED068: compare number of trys |
??? | input??? | output??? |
Determine Encounter Slot | 0x0223C5AC | 0x0223C647? | ??? | R0: Index of Encounter Slot |
??? | ???
0x223CAC6, Determine Encounter Slot |
??? | ||
First Wondercard (japanese Soulsilver, onscreen)???? | 0x02285DE0 | |||
Box02 (japanese Soulsilver, onscreen)???? | 0x0228BE04 |
Sometimes you may encounter some numbers that may look strange at first. In many cases the purpose of a function gets more understandable if you're able to recognize those numbers and their meaning.
hex | dec | Description |
---|---|---|
0x27 | 39 | 0x270 = 0x27 << 4 |
0x00000183 | 387 | Pokedex number of Turtwig (starter1) |
0x00000186 | 390 | Pokedex number of Chimchar (starter2) |
0x00000189 | 393 | Pokedex number of Piplup (starter3) |
up to 0x000001ED | up to 493 | Numbers up to 0x1ED may be pokedex numbers |
0x270 | 624 | Size of Mersenne table |
0x00002008 | 8200 | = 41*200, used by pokeradar |
0x00006073 | 24691 | Used in PRNG, Addition |
0x0000FFFF | 65535 | Bitmask: Lower 16 bit |
0x41C64E6D | 1103515245 | Used in PRNG, Multiplication |
0x6C078965 | 1812433253 | Used in Mersenne_init (multiplication)
also used in Masuda Cycle (multiplication) |
0x9D2C5680 | 2636928640 | Used in Mersenne (tempering) |
0xFFFF0000 | 4294901760 | Bitmask: Upper 16 bit |
CMP Rn,Rm -> alu_out = Rn - Rm
EQ | Z is set, if Rn=Rm |
---|---|
NE | Z is clear if Rn!=Rm |
LT | V can never be set if both operands are positive.
N is set for Rn<Rm |
GT | Z is clear if Rn!=Rm
V can never be set if both operands are positive. N is clear for Rn>=Rm |
Offset
address | opcode | command | alias | comment |
---|---|---|---|---|
Mersenne Init | ||||
0x0201BA1C | B430 | PUSH R6,R5 | push r5-r6 | Pushes some values onto the stack (but not lr) |
0x0201BA1E | 490C | LDR R1 PC+(12*4) | r1 = mem[PC+0x30]
r1 = mem[0x0201BA22+0x30] r1 = mem[0x0201BA20+0x30] r1 = mem[0x0201BA50] r1 = 0x021C4D48 |
Load address of seed into R1 |
0x0201BA20 | 2427 | MOV R4, 0x27 | r4 = 0x27 | Load a constant into r4 |
0x0201BA22 | 6048 | STR R0 [R1+1*4] | mem[R1+0x04] = r0
mem[0x021C4D48+0x04] = r0 mem[0x021C4D4C] = r0 |
Store given value (starting seed M0) in memory |
0x0201BA24 | 490B | LDR R1 PC+(11*4) | r1 = mem[PC+0x2C]
r1 = mem[0x0201BA28+0x2C] r1 = mem[0x0201BA54] r1 = 0x02105BA8 |
Load next address into R1 |
0x0201BA26 | 2001 | MOV R0, 0x01 | r0 = 0x01 | load another constant, into R0 |
0x0201BA28 | 6008 | STR R0 [R1+0*4] | mem [r1+0x00] = r0
mem [0x02105BA8] = 0x01 |
Write constant One into address |
0x0201BA2A | 490B | LDR R1 PC+(11*4) | r1 = mem[PC+0x2C]
r1 = mem[0x0201BA2E+0x2C] r1 = mem[0x0201BA2C+0x2C] r1 = mem[0x0201BA58] r1 = 0x021C4D50 |
Load address (right behind the one just written) |
0x0201BA2C | 4B0B | LDR R3 PC+(11*4) | r3 = mem[PC+0x2C]
r3 = mem[0x0201BA30+0x2C] r3 = mem[0x0201BA5C] r3 = 0x6C078965 |
Load Masuda factor |
0x0201BA2E | 0124 | LSL R4,R4,4 | r4 = r4 << 4
r4 = 0x27 <<4 r4 = 0x270 |
Increase the value from earlier |
0x0201BA30 | 1F0A | SUB R2,R1,4 | r2 = r1 - 0x04 | (Begin of loop) Load address of last stored number
At first iteration, this is address of M0 |
0x0201BA32 | 6815 | LDR R5, [R2+0x00] | r5 = mem[R2+0x00] | Restore previous stored number
At first iteration, this is M0, the first given seed |
0x0201BA34 | 0FAA | LSR R2,R5,30 | r2 = r5 >>0x1e | Isolates upper 2 bit from r5 |
0x0201BA36 | 406A | EOR R2, R5 | r2 = r2 xor r5
r2 = (r5>>0x1e) xor r2 |
lower 2 bit of r2 get influenced by previous upper 2 bit |
0x0201BA38 | 1C15 | ADD R5,R2,0x00 | r5 = r2 + 0x00
r5 = r2 |
Copy manipulated value back to R5 |
0x0201BA3A | 435D | MUL R5,R3 | r5 = r5 * r3
r5 = r5 * 0x6C078965 |
Multiply manipulated value with mersenne factor |
0x0201BA3C | 1942 | ADD R2,R5,R0 | r2 = r5 + r0 | Increase number by count |
0x0201BA3E | 1C40 | ADD R0,R0,0x01 | r0 = r0 + 0x01 | increase r0 (for next cycle) |
0x0201BA40 | C104 | STMIA R1, (r2-r2) | mem[r1]=r2; r1=r1+regcount*0x4
mem[r1]=r2; r1=r1+0x4 |
Store this value and postincrement R1 |
0x0201BA42 | 42A0 | CMP R4,R0 | cmp r4,r0
cmp 0x270,r0 |
0x270 = 624 = number of entrys for table |
0x0201BA44 | DBF4 | B LT (-0x18) | if (r0<0x270) PC = 0x0201BA48-0x18
if (r0<0x270) PC= 0x0201BA30 |
If not all 624 entrys finished, continue loop |
0x0201BA46 | 4903 | LDR R1, PC+(3*4) | r1 = mem[0x0201BA4A+0xC]
r1 = mem[0x0201BA48+0xC] r1 = mem[0x0201BA54] r1 = 0x02105BA8 |
Load address (0x1 was stored here) |
0x0201BA48 | 6008 | STR R0,R1+0*4 | mem[r1+0x00] = r0
mem[0x02105BA8] = r0 mem[0x02105BA8] = 0x270 |
Store number of calculated table entrys? current index? |
0x0201BA4A | BC30 | POP R6,R5 | pop r5-r6 | Restore stacked values (not end of function |
0x0201BA4C | 4707 | BX R7 | PC = r7 | end of function, return |
Mersenne RNG | ||||
0x0201BA60 | B5F8 | PUSH LR, R7, R6, R5, R4, R3 | push r3-r7, lr | Save some values on stack |
0x0201BA62 | 4838 | LDR R0, PC+(56*4) | r0 = mem[0x0201BA66+0xE0]
r0 = mem[0x0201BB46] r0 = mem[0x0201BB44] r0 = 0x02105BA8 |
Load address of Mersenne index into R0 |
0x0201BA64 | 6801 | LDR R1, R0+0*4 | r1 = mem[r0+0x00]
r1 = mem[0x02105BA8] |
Load Mersenne index into R1 |
0x0201BA66 | 2027 | MOV R0,39 | r0 = 0x27 | Load a constant (preparation for 0x270) |
0x0201BA68 | 0100 | LSL R0, R0, 4 | r0 = r0 << 4
r0 = 0x27<<4 r0 = 0x270 |
Load Mersenne table size |
0x0201BA6A | 4281 | CMP R1,R0 | cmp r1,0x270 | Compare current index with table size |
0x0201BA6C | DB54 | B LT (84) | if (r1<0x270) PC = 0x0201BA70+0xA8
if (r1<0x270) PC = 0x0201BB18 |
If index is small, jump |
0x0201BA6E | 1C40 | ADD R0,R0,0x1 | r0 = r0 + 0x1 | r0 = 0x271? |
0x0201BA70 | 4281 | CMP R1,R0 | cmp r1,0x271? | Compare index with next size |
0x0201BA72 | D102 | B NE (2) | if (r1 != 0x271) PC = 0x0201BA76+0x4
if (r1 != 0x271) PC = 0x0201BA7A |
If index is exact, jump |
0x0201BA74 | 4834 | LDR R0, (PC+52*4) | r0 = mem[0x0201BA78+0xD0]
r0 = mem[0x0201BB48] |
load next address |
0x0201BA76
0x0201BA78 |
F7FF
FFD1 |
BL, high: 0x7FF
BL, low: 0x7D1 |
call (PC+high<<12+low<<1)
call (0x0201BA7A-0x1000+0xFA2) call 0x0201BA1C |
Re-Init Mersenne? |
0x0201BA7A | 4C34 | LDR R4, (PC+52*4) | r4 = mem[0x0201BA7E+0xD0]
r4 = mem[0x0201BB4E] r4 = mem[0x0201BB4C] r4 = 0x021C4D4C |
Load address (begin of mersenne table) |
0x0201BA7C | 4934 | LDR R1, (PC+52*4) | r1 = mem[0x0201BA80+0xD0]
r1 = mem[0x0201BB50] r1 = 0x02105BAC |
Load another address |
0x0201BA7E | 4D35 | LDR R5, (PC+53*4) | r5 = mem[0x0201BA82+0xD4]
r5 = mem[0x0201BB56] r5 = mem[0x0201BB54] r5 = 0x7FFFFFFF |
Load an interesting constant |
Pokeradar something | ||||
0x0205DED4 | B5F8 | PUSH LR, R7, R6, R5, R4, R3 | push r3-r7, lr | Save some values on stack |
TODO | ||||
0x0205DF30
0x0205DF32 |
F000
FA6C |
BL, high: 0x
BL, low: 0x |
call (PC+high<<12+low<<2)
call (PC+ ... call 0x0205E40C |
Call Shiny Check for chaining |
TODO | ||||
0x0205DF42 | BDF8 | POP LR, R7, R6, R5, R4, R3 | pop r3-r7, lr | restore values from stack |
Pokeradar try | ||||
0x0205E30C | B5F8 | PUSH LR, R7, R6, R5, R4, R3 | push r3-r7, lr | Save some values on stack |
TODO | ||||
0x0205E34A | 1C06 | ADD R6, R0, 0 | r6 = r0 + 0
r6 = r0 |
Copy r0 (address) to r6 |
0x0205E34C | 7830 | LDR R0 R6+0 | r0 = mem[r6+0]
r0 = mem[r6] |
Get steps since last usage |
0x0205E34E | 2832 | TODO | cmp r0, 0x32 | At this point, r0 ist number of steps since pokeradar was used last time.
It is compared against 50 - so only after 50 steps, it may be used again. |
TODO | ||||
0x0205E3EB | BDF8 | POP LR, R7, R6, R5, R4, R3 | pop r3-r7, lr | restore values from stack |
Shiny Check for Chaining | ||||
0x0205E40C | B538 | PUSH LR,R5,R4,R3 | push r3-r5, lr | Those values are likely to be overwritten and therefore are saved on the stack |
0x0205E40E | 2800 | CMP R0, 0x00 | Z = (r0 == 0x00) | Compare R0 (chain size) with zero |
0x0205E410 | D101 | B NE 0x01*2 | if (!Z), PC=PC+2
if (r0 != 0), PC=0x0205E416 |
If chainsize is not zero jump to rest of function |
0x0205E412 | 2000 | MOV R0 0x00 | r0=0 | Prepare zero (false) for return in R0 |
0x0205E414 | BD38 | POP PC,R5,R4,R3 | pop r3-r5,PC | End of funtion, restore values
Note that this last two lines (early termination of function) are only executed, when R0 = 0 (chain size = 0) |
0x0205E416 | 1C02 | ADD R2, R0, 0x00 | r2 = r0 + 0x00
r2 = r0 |
Copy chain size to R2 |
0x0205E418 | 21C8 | MOV R1, 0xC8 | r1 = 0xC8 | 0xC8 = 200, used in calculation |
0x0205E41A | 4817 | LDR R0 PC+(0x17*4) | r0 = mem[PC+0x5C]
r0 = mem[0x0205E41E+0x5C] r0 = mem[0x0205E41C+0x5C] r0 = mem[0x0205E478] r0 = 0x00002008 |
0x2008 = 8200, used in calculation |
0x0205E41C | 434A | MUL R2, R1 | r2 = r2 * r1
r2 = r2 * 200 |
Multiply chain size with 200 |
0x0205E41E | 1A85 | SUB R5 R0 R2 | r5 = r0 - r2
r5 = 8200-r2 r5 = 8200-(chainsize*200) |
With chainsize near 40, the result is interesting
chainsize 39: r5=400 chainsize 40: r5=200 chainsize 41: r5=0 chainsize 42: r5 negative |
0x0205E420 | 2DC8 | CMP R5, 0xC8 | cmp r5, 0xC8 | Compare chainsize with constant 200. |
0x0205E422 | DA00 | B GT 0x00*2 | if (...) PC=PC+0
if (...) PC = 0205E426 |
if R5 is larger than 200 (chainsize less than 40),
skip correction. |
0x0205E424 | 1C0D | ADD R5 R1 0x00 | r5 = r1 + 0
r5 = r1 r5 = 200 |
Correction: If chainsize was 40 or larger, correct r5 as if chainsize was exactly 40.
This makes chains larger 40 useless |
0x0205E426 | 0428 | LSL R0, R5, 0x10 | r0 = r5 << 16 | Puts R5 into R0 (with a little bitshift) |
0x0205E428 | 0C00 | LSR R0,R0,0x10 | r0 = r0 >> 16 | Shifts value down again.
Effectively, the last two instructions move r5 to r0 while killing the upper 16 bit. For maximum chain size, R0 now is 200=0xC8 |
0x0205E42A | D101 | B NE 0x01*2 | if (!Z), PC=PC+2
if (r0!=0), PC=0x0205E430 |
As R0 never is zero at this point, this conditional branch always branches. |
0x0205E42C
0x0205E42E |
F7C2
FBFE |
BL, high: 0x7C2
BL, low: 0x3FE |
call (PC+high<<12+low<<2)
call (PC+0xFFC2000+0x7FC) call (PC-0x3E000+0x7FC) call (0x0205E430-0x3E000+0x7FC) call 0x02020C2C |
This is a pretty wild uncondional jump that I didn't bother analyzing any further -
as it is only executed if r0 is zero at a point it always will be zero |
0x0205E430 | 0428 | LSL R0, R5, 0x10 | r0 = r5 << 16 | Puts R5 into R0 (with a little bitshift) |
0x0205E432 | 0C00 | LSR R0,R0,0x10 | r0 = r0 >> 16 | Shifts value down again.
Effectively, the last two instructions move r5 to r0 while killing the upper 16 bit. For maximum chain size, R0 now is 200=0xC8. Last two lines repeat 0x0205E426. I can only assume that the function at 0x02020C2C can destroy R0 and that's why it is calculated, again. Still, as long as 02020C2C is not called from here, this should be unnecessary |
0x0205E434 | 2801 | CMP R0 0x01 | cmp r0,0x01 | Compare R0 (still calculated from chain size) with 0x01
Note, r0 is 200 for maximum chain size and larger for shorter chains. |
0x0205E436 | D801 | B HI 0x01*2 | if (...) PC=PC+0x02
if (...) PC=0205E43C |
R0 is far from being 1, so this always branches.
But consider R0 being 1 at this point... |
0x0205E438 | 2400 | MOV R4 0x00 | r4=0x00 | Set R4 to zero
(code line never reached) |
0x0205E43A | E016 | B 0x16*2 | PC = PC+0x2C
PC = 0x0205E46A |
Again, this is not executed |
0x0205E43C
0x0205E43E |
F7BD
FAD6 |
BL, high: 0x7BD
BL, low: 0x2D6 |
call (0x0205E440-0x43000+0x5AC)
call 0x0201B9EC r0 = prng() |
get a random number |
0x0205E440 | 1C04 | ADD R4 R0 0x00 | r4 = r0 + 0
r4 = r0 |
copy the random number into R4 |
0x0205E442 | 0429 | LSL R1 R5 0x10 | r1 = r5 << 16 | again, moves R5 (200 for max chainsize) with shift.
This time is is put into R1 |
0x0205E444 | 480D | LDR R0 PC+(0x0D*4) | r0 = mem [PC+0x34]
r0 = mem [0x0205E448 + 0x34] r0 = mem [0x0205E47C] r0 = 0x0000ffff |
65535 is needed for division |
0x0205E446 | 0C09 | LSR R1 R1 0x10 | r1 = r1 >> 16 | Finally, R5 really has arrived, here. |
0x0205E448
0x0205E44A |
F08D
EC1A |
BLX; high: 0x8D
BLX; low: 0x41A |
call (0x0205E44C+0x8D000+0x834)
call 0x020EBC80 r0 = r0 / r1; r1 = r0 % r1 |
r0 = 65535 / (8200 - chainsize*200)
for max chainsize: r0 = 65535 / 200 = 327 |
0x0205E44C | 1C01 | ADD R1 R0 0 | r1 = r0 + 0
r1 = r0 |
copy to r1 |
0x0205E44E | 1C49 | ADD R1 R1 1 | r1 = r1 + 1 | for max chainsize: r1 = 328 |
0x0205E450 | 0409 | LSL R1 R1 0x10 | r1 = r1 << 16 | Another shift with following backshift |
0x0205E452 | 1C20 | ADD R4 R0 0x00 | r0 = r4 + 0
r0 = r4 |
Copy random number back to r0 |
0x0205E454 | 0C09 | LSR R1 R1 0x10 | r1 = r1 >> 16 | this is the backshift. For max chainsize r1 = 328 |
0x0205E456
0x0205E458 |
F08D
EC14 |
BLX; high: 0x8D
BLX; low: 0x414 |
call (0x0205E45A+0x8D000+0x828)
call 0x020EBC82 call 0x020EBC80 r0 = r0 / r1; r1 = r0 % r1 |
The random number is divided by the previously calculated value.
For max chainsize, this means random/328 This is 0 for random lesser than 328 |
0x0205E45A | 0400 | LSL R0 R0 0x10 | r0 = r0 << 16 | Although division result shouldn't have any high bits,
another shifting is done |
0x0205E45C | 0C04 | LSR R4 R0 0x10 | r4 = r0 >> 16 | So the division result is put into r4 |
0x0205E45E | 0428 | LSL R0 R5 0x10 | r0 = r5 << 16 | 8200 - chainsize*200 (maxchain: 200) starts a journey into R0 |
0x0205E460 | 0C00 | LSR R0 R0 0x10 | r0 = r0 >> 16 | 8200 - chainsize*200 (maxchain: 200) arrives in R0 |
0x0205E462 | 4284 | CMP R4 R0 | cmp r4 r0 | r4 is the division result (range: 0 to 8191, smaller range with longer chainsize)
r0 is the "converted" chainsize (200 - 8000) |
0x0205E464 | D301 | B CC/LO 0x01*2 | if (r4<r0) jump 0x0205E46A | As r0 has to be zero for shiny, jump is unwanted |
0x0205E466
0x0205E468 |
F7C2
FBE1 |
BL; high: 0x7C2
BL; low: 0x4E1 |
call (PC+0x7C2<<12+0x4E1*2)
call (0x0205E46A-0x3E000+7C2) call 0x02020C2C |
(yet) no idea, what this function does. |
0x0205E46A | 2C00 | CMP R4, 0x00 | cmp r4, 0x00 | R4 has to be zero for the routine to return true |
0x0205E46C | D101 | B NE 0x01*2 | if (r4!=0x00) PC=0x0205E472 | Skip return of true |
0x0205E46E | 2001 | MOV R0 0x01 | r0 = 0x01 | Prepare one (true) for return in R0 |
0x0205E470 | BD38 | POP PC,R5,R4,R3 | pop r3-r5,PC | End of funtion, restore values
Note that this last two lines are only executed, when R4 = 0 |
0x0205E472 | 2000 | MOV R0 0x00 | r0 = 0x00 | Prepare zero (false) for return in R0 |
0x0205E474 | BD38 | POP PC,R5,R4,R3 | pop r3-r5,PC | End of function, restore values
Note that this last two lines are only executed, when R4 != 0 |
Check if PID is shiny | ||||
0x02068AAC | 4B09 | LDR R3, PC+(9*4) | r3 = mem[PC+0x24]
r3 = mem[0x02068AB0 + 0x24] r3 = mem[0x02068AD4] r3 = 0xffff0000 |
Load a bitmask (upper 16 bit) |
0x02068AAE | 040A | LSL R2 R1 0x10 | r2 = r1 << 16 | As R1 is PID: load PID.LOW into R2(high) |
0x02068AB0 | 4019 | AND R1 R3 | r1 = r1 and r3 | isolates PID.HIGH in R1(high) |
0x02068AB2 | 4003 | AND R3, R0 | r3 = r3 and r0 | R0 is SIDTID, R3(high) gets SID |
0x02068AB4 | 0400 | LSL R0 R0 0x10 | r0 = r0 << 16 | As R0 is SIDTID, load TID into R0(high) |
0x02068AB6 | 0C1B | LSR R3 R3 0x10 | r3 = r3 >> 16 | SID moves into lower bits of R3 |
0x02068AB8 | 0C00 | LSR R0 R0 0x10 | r0 = r0 >> 16 | TID moves into lower bits of R0 |
0x02068ABA | 0C09 | LSR R1 R1 0x10 | r1 = r1 >> 16 | PID.high into lower bits of R1 |
0x02068ABC | 4058 | EOR R0 R3 | r0 = r0 xor r3 | calculates trainer.XID into R1 |
0x02068ABE | 0C12 | LSR R2 R2 0x10 | r2 = r2 >> 16 | PID.low into lower bits of R2 |
0x02068AC0 | 4048 | EOR R0 R1 | r0 = r0 xor r1 | merges trainer.XID with PID.high |
0x02068AC2 | 4050 | EOR R0 R2 | r0 = r0 xor r2 | finally, merge PID.low into the rest |
0x02068AC4 | 2808 | CMP R0 0x08 | cmp r0 0x08 | If at this point R0 is <8, the PID is shiny for given SIDTID |
0x02068AC6 | D201 | B CS/HS 0x01*2 | if (r0>=0x08) PC=0x02068ACC | R0 is too high, jump to negative result |
0x02068AC8 | 2001 | MOV R0 0x01 | r0 = 1 | PID is shiny, prepare true (1) as return value in R0 |
0x02068ACA | E000 | B 0x00*2 | PC = 0x02068ACE | jump to end of function |
0x02068ACC | 2000 | MOV R0 0x00 | r0 = 0 | PID is nonshiny, prepare false (0) as return value in R0 |
0x02068ACE | 0600 | LSL R0 R0 0x18 | r0 = r0 <<24 | false still is 0, true gets shifted up |
0x02068AD0 | 0E00 | LSR R0 R0 0x18 | r0 = r0 >>24 | and shift down again (unneccessary overflow protection?) |
0x02068AD2 | 4770 | BX R14 | bx lr | End of Function |
PRNG-style, german soulsilver | ||||
0x02009CB0 | 6802 | LDR R2, R0, 0 | R2 = mem[R0+0]
R2 = mem[R0] |
R0 seems to be location of current seed |
0x02009CB2 | 4905 | LDR R1, +5 | R1 = mem{PC+5*4)
R1 = mem[0x02009CB6+14] R1 = mem[0x02009CCA] R1 = mem[0x02009CC8] R1 = 0x41C64E6D |
Multiplicative part of PRNG |
0x02009CB4 | 1C13 | ADD R3, R2, 0 | R3 = R2 + 0x00
R3 = R2 |
Current Seed? |
0x02009CB6 | 434B | MUL R3, R1 | R3 = R3 * R1
R3 = R3 * 0x41C64E6D |
Multiplication |
0x02009CB8 | 4904 | LDR R1, +0 | R1 = mem [PC+4*4]
R1 = mem[0x02009CBC+0x10] R1 = mem[0x02009CCC] R1 = 0x6073 |
Additive part of PRNG |
0x02009CBA | 1859 | ADD R1, R1, R3 | R1 = R1 + R3
R1 = 0x6073 + R3 |
Addition |
0x02009CBC | 6001 | STR R0,+0,R1 | mem[R0+0]=R1 | Store new seed |
0x02009CBE | 0C08 | LSR R0, R1, 0x10 | R0 = R1 >> 16 | push high to low |
0x02009CC0 | 0400 | LSL R0, R0, 0x10 | R0 = R0 << 16 | push low to high |
0x02009CC2 | 0C00 | LSR R0, R0, 0x10 | R0 = R0 >> 16 | push high to low again |
0x02009CC4 | 4770 | BX R14 | bx r14 | End of function |