- Thread starter Arseus
- Start date

- Status
- Not open for further replies.

they're all exactly the same. if it's different it's a result of your gba acting strangely. or if you're using a ds you'll get different results too. timer1 runs at 16.78mhz on a gba and 33.something mhz on a ds.

e: the F(system clock) that timer1 runs against is the speed of the arm7 cpu in both cases. so.. that's why it's different. it's moving at the speed of the cpu.

e: the F(system clock) that timer1 runs against is the speed of the arm7 cpu in both cases. so.. that's why it's different. it's moving at the speed of the cpu.

-------

As I've already caught mewtwo, I've had to make do with zapdos, but that's not troubling me in the slightest. One thing that IS troubling me, however, is that my frame seems to be dependent upon how long I stay in the "recollection of your past events" scenes. I dunno if this has happened to anyone else, but once I get out of the recollections my frame seems to just

On another note, I've discovered some additional seed groupings (and hit some old ones as well), but I'll edit those in later when I have more data.

How do I quickly find my seed from the information I have about the Pokemon I caught?

The FRLGSeedFinder requires me to type in a Seed. So I am confused.

The FRLGSeedFinder requires me to type in a Seed. So I am confused.

So when trying to find an initial seed you commonly hit do this (v9.81):

1. Capture a high level Pokemon.

2. Check it's IVs using Metal kid.

3. Go on to the RNG Reporter (9.81).

4. Click '4th Gen Tools' at the top.

5. Click 'Calculate PID from IVs'.

6. Type in the Nature and IVs of the Pokemon you caught.

7. Find which of the results it the correct Method. (Method 1 for stationary Pokemon as in first post, Method 2 for wild Pokemon)

8. Type out the Seed that was generated into the App attached to the first post.

9. One of the new 4 hex-digit long Seeds is your Initial Seed. (4 hex-digits is 2-bytes). The Seeds starting: 54... 30... 0b... or 9e... are probably yours.

imo Smogon has good guides but need to be written simpler.

e.g. The bit about catching a Pokemon and checking it's IVs with the equations and calling it TCheck is basically this:

If you're trying to get a high frame and have time to check IVs then:

1. Capture a wild Pokemon with Sweet Scent while your timer is running waiting for the right frame.

2. Follow the steps above for finding your Initial Seed.

3. If you hit the right Seed then carry on waiting. If it's wrong don't wait around and start again.

Note: It might be a good idea to see how long it takes you to check IVs so you know if you have enough time to verify your Initial Seed before your Target Frame appears.

While you're sweet scenting, several frames are skipped, and then the game enters

Zari picked a small enough frame so that he wouldn't have to check his seed before battling Mewtwo, so he probably didn't run into this problem.

While you're sweet scenting, several frames are skipped, and then the game enters

Zari picked a small enough frame so that he wouldn't have to check his seed before battling Mewtwo, so he probably didn't run into this problem.

It's problematic to trace back to what frame you had originally hit, but with enough work it's possible.

edit: fine, "noisy" just means that the vblank advancement isnt the only thing advancing. There's NPCs, battles, wild cries, etc.

My point was that if you're trying this on a cart, and you have a 16 min spread, you can't check your seed, and then expect to hit the right frame 16 minutes in. Sure, you'll know your seed, but you'll probably be several thousand frames off.

Not exactly, the whole "Noisy" phenomenon is the Method H at work, essentially Method K.

It's problematic to trace back to what frame you had originally hit, but with enough work it's possible.

It's problematic to trace back to what frame you had originally hit, but with enough work it's possible.

-------------------------------

So I've been sitting on this for about a week tryng to decide how to go about making this post and having it be at least mostly understandable to everyone. I don;t think that I quite can, so we're just going to have to go with this.

First, let's consider pokemon creation:

This is Method H in a nutshell:(the numbers are the locations in the ROM where the routines run from)

-------------------------------

080B5144 Battle test

080B4AC8 Encounter slot

080B4C74 Set level

080B4E2A Sync(bool)

080B4E4C Nature setup/decision(skip if(sync() == TRUE))

08067E96 PKM building routine(test temp PIDs, make IVs on success)

Now, obviously, all of those decisions need to be made using the RNG. The way Gamefreak decided to handle that was through a very simple method of taking the current result of their rand() function and using modulus to produce a number within the range they wanted. A number mod another number produces a value between 0 and the second number minus 1. So, a %(mod) b will result in a value between 0 and b-1, so it's very simple and it works. If you need a number between 1 and 100. just do a % 100 and you get results between 0 and 99, so 100 numbers. Anyway, this is used for basically everything. And all of these modulus operations are done with one specific routine:

082E7BE0 Modulus routine- r0 % r1, return result in r0

**As a quick refresher, the way Method H/J/K(basically) work is that the game takes a seed and does (seed >> 16) % 0x19. Then it starts making PIDs and doing PID % 0x19 and it keeps making PIDs until it gets a match to that original (seed >> 16) % 0x19.**

What this would look like in C(the game is written in the C programming language) is something like:

ushort getMod(ushort random, int m)

{return (ushort)(random % m);}

So, knowing that, why do we need to dwell on the formulas and modulus? Because they themselves are the root of the issue that causes the methods to occur. This is an excerpt from an ARM Application Note(#34, ARM DAI #0034A) regarding using division and (by association) the modulus operation:

The ARM instruction set does not provide integer division. Divisions are typically

implemented by calling a C-library function (__rt_sdiv for signed and __rt_udiv for

unsigned division). Depending on the numerator and denominator, a 32-bit division takes

20-140 cycles. The division function takes a constant time plus a time for each bit to

divide:

Time(numerator / denominator)

= C0 + C1 * log2(numerator / denominator) =

= C0 + C1 * (log2(numerator) - log2(denominator)).

The current version takes about 20 + 4.3N cycles.

**As division is an expensive operation, it is desirable to avoid it where possible.** Sometimes

expressions can be rewritten so that a division becomes a multiplication. For example,

(x / y) > z can be rewritten as x > (z * y) if it is known that y is positive and y * z

fits in an integer.

It is best to use unsigned division by ensuring that one of the operands is unsigned, as this

is faster than signed division. This applies both to the division subroutines and to divisions

by a power of two (see 3.2 Division and remainder by powers of two).

implemented by calling a C-library function (__rt_sdiv for signed and __rt_udiv for

unsigned division). Depending on the numerator and denominator, a 32-bit division takes

20-140 cycles. The division function takes a constant time plus a time for each bit to

divide:

Time(numerator / denominator)

= C0 + C1 * log2(numerator / denominator) =

= C0 + C1 * (log2(numerator) - log2(denominator)).

The current version takes about 20 + 4.3N cycles.

expressions can be rewritten so that a division becomes a multiplication. For example,

(x / y) > z can be rewritten as x > (z * y) if it is known that y is positive and y * z

fits in an integer.

It is best to use unsigned division by ensuring that one of the operands is unsigned, as this

is faster than signed division. This applies both to the division subroutines and to divisions

by a power of two (see 3.2 Division and remainder by powers of two).

That's right, 4 times as many cycles used (on average) per computation when doing out Method H and checking to see if PID % 0x19 matches (seed >> 16) % 0x19.

Now, to further compare how bloated this is, let's compare the gen 3 modulus function with the divmod used in gen 4 and 5

Gen 3 modulus function:

Code:

```
082E7BE0 2900 cmp r1,#0x0
082E7BE2 D058 beq #0x82E7C96
082E7BE4 2301 mov r3,#0x1
082E7BE6 4288 cmp r0,r1
082E7BE8 D200 bcs #0x82E7BEC
082E7BEA 46F7 mov r15,r14
082E7BEC B410 push {r4}
082E7BEE 2401 mov r4,#0x1
082E7BF0 0724 lsl r4,r4,#0x1C
082E7BF2 42A1 cmp r1,r4
082E7BF4 D204 bcs #0x82E7C00
082E7BF6 4281 cmp r1,r0
082E7BF8 D202 bcs #0x82E7C00
082E7BFA 0109 lsl r1,r1,#0x4
082E7BFC 011B lsl r3,r3,#0x4
082E7BFE E7F8 b #0x82E7BF2
082E7C00 00E4 lsl r4,r4,#0x3
082E7C02 42A1 cmp r1,r4
082E7C04 D204 bcs #0x82E7C10
082E7C06 4281 cmp r1,r0
082E7C08 D202 bcs #0x82E7C10
082E7C0A 0049 lsl r1,r1,#0x1
082E7C0C 005B lsl r3,r3,#0x1
082E7C0E E7F8 b #0x82E7C02
082E7C10 2200 mov r2,#0x0
082E7C12 4288 cmp r0,r1
082E7C14 D300 bcc #0x82E7C18
082E7C16 1A40 sub r0,r0,r1
082E7C18 084C lsr r4,r1,#0x1
082E7C1A 42A0 cmp r0,r4
082E7C1C D305 bcc #0x82E7C2A
082E7C1E 1B00 sub r0,r0,r4
082E7C20 469C mov r12,r3
082E7C22 2401 mov r4,#0x1
082E7C24 41E3 ror r3,r4
082E7C26 431A orr r2,r3
082E7C28 4663 mov r3,r12
082E7C2A 088C lsr r4,r1,#0x2
082E7C2C 42A0 cmp r0,r4
082E7C2E D305 bcc #0x82E7C3C
082E7C30 1B00 sub r0,r0,r4
082E7C32 469C mov r12,r3
082E7C34 2402 mov r4,#0x2
082E7C36 41E3 ror r3,r4
082E7C38 431A orr r2,r3
082E7C3A 4663 mov r3,r12
082E7C3C 08CC lsr r4,r1,#0x3
082E7C3E 42A0 cmp r0,r4
082E7C40 D305 bcc #0x82E7C4E
082E7C42 1B00 sub r0,r0,r4
082E7C44 469C mov r12,r3
082E7C46 2403 mov r4,#0x3
082E7C48 41E3 ror r3,r4
082E7C4A 431A orr r2,r3
082E7C4C 4663 mov r3,r12
082E7C4E 469C mov r12,r3
082E7C50 2800 cmp r0,#0x0
082E7C52 D003 beq #0x82E7C5C
082E7C54 091B lsr r3,r3,#0x4
082E7C56 D001 beq #0x82E7C5C
082E7C58 0909 lsr r1,r1,#0x4
082E7C5A E7D9 b #0x82E7C10
082E7C5C 240E mov r4,#0xE
082E7C5E 0724 lsl r4,r4,#0x1C
082E7C60 4022 and r2,r4
082E7C62 D101 bne #0x82E7C68
082E7C64 BC10 pop {r4}
082E7C66 46F7 mov r15,r14
```

Gen 4/5 divmod:

Code:

```
:0209C2C8 E3510000 cmp r1,#0x0
:0209C2CC 012FFF1E bxeq r14
:0209C2D0 E1500001 cmp r0,r1
:0209C2D4 31A01000 movcc r1,r0
:0209C2D8 33A00000 movcc r0,#0x0
:0209C2DC 312FFF1E bxcc r14
:0209C2E0 E3A0201C mov r2,#0x1C
:0209C2E4 E1A03220 mov r3,r0,lsr #0x4
:0209C2E8 E1510623 cmp r1,r3,lsr #0xc
:0209C2EC D2422010 suble r2,r2,#0x10
:0209C2F0 D1A03823 movle r3,r3,lsr #0x10
:0209C2F4 E1510223 cmp r1,r3,lsr #0x4
:0209C2F8 D2422008 suble r2,r2,#0x8
:0209C2FC D1A03423 movle r3,r3,lsr #0x8
:0209C300 E1510003 cmp r1,r3
:0209C304 D2422004 suble r2,r2,#0x4
:0209C308 D1A03223 movle r3,r3,lsr #0x4
:0209C30C E1A00210 mov r0,r0,lsl r2
:0209C310 E2611000 rsb r1,r1,#0x0
:0209C314 E0900000 adds r0,r0,r0
:0209C318 E0822082 add r2,r2,r2,lsl #0x1
:0209C31C E08FF102 add r15,r15,r2,lsl #0x2
:0209C320 E1A00000 nop(mov r0,r0)mov r0,r0
:0209C324 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C328 30433001 subcc r3,r3,r1
:0209C32C E0B00000 adcs r0,r0,r0
:0209C330 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C334 30433001 subcc r3,r3,r1
:0209C338 E0B00000 adcs r0,r0,r0
:0209C33C E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C340 30433001 subcc r3,r3,r1
:0209C344 E0B00000 adcs r0,r0,r0
:0209C348 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C34C 30433001 subcc r3,r3,r1
:0209C350 E0B00000 adcs r0,r0,r0
:0209C354 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C358 30433001 subcc r3,r3,r1
:0209C35C E0B00000 adcs r0,r0,r0
:0209C360 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C364 30433001 subcc r3,r3,r1
:0209C368 E0B00000 adcs r0,r0,r0
:0209C36C E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C370 30433001 subcc r3,r3,r1
:0209C374 E0B00000 adcs r0,r0,r0
:0209C378 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C37C 30433001 subcc r3,r3,r1
:0209C380 E0B00000 adcs r0,r0,r0
:0209C384 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C388 30433001 subcc r3,r3,r1
:0209C38C E0B00000 adcs r0,r0,r0
:0209C390 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C394 30433001 subcc r3,r3,r1
:0209C398 E0B00000 adcs r0,r0,r0
:0209C39C E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3A0 30433001 subcc r3,r3,r1
:0209C3A4 E0B00000 adcs r0,r0,r0
:0209C3A8 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3AC 30433001 subcc r3,r3,r1
:0209C3B0 E0B00000 adcs r0,r0,r0
:0209C3B4 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3B8 30433001 subcc r3,r3,r1
:0209C3BC E0B00000 adcs r0,r0,r0
:0209C3C0 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3C4 30433001 subcc r3,r3,r1
:0209C3C8 E0B00000 adcs r0,r0,r0
:0209C3CC E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3D0 30433001 subcc r3,r3,r1
:0209C3D4 E0B00000 adcs r0,r0,r0
:0209C3D8 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3DC 30433001 subcc r3,r3,r1
:0209C3E0 E0B00000 adcs r0,r0,r0
:0209C3E4 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3E8 30433001 subcc r3,r3,r1
:0209C3EC E0B00000 adcs r0,r0,r0
:0209C3F0 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C3F4 30433001 subcc r3,r3,r1
:0209C3F8 E0B00000 adcs r0,r0,r0
:0209C3FC E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C400 30433001 subcc r3,r3,r1
:0209C404 E0B00000 adcs r0,r0,r0
:0209C408 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C40C 30433001 subcc r3,r3,r1
:0209C410 E0B00000 adcs r0,r0,r0
:0209C414 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C418 30433001 subcc r3,r3,r1
:0209C41C E0B00000 adcs r0,r0,r0
:0209C420 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C424 30433001 subcc r3,r3,r1
:0209C428 E0B00000 adcs r0,r0,r0
:0209C42C E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C430 30433001 subcc r3,r3,r1
:0209C434 E0B00000 adcs r0,r0,r0
:0209C438 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C43C 30433001 subcc r3,r3,r1
:0209C440 E0B00000 adcs r0,r0,r0
:0209C444 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C448 30433001 subcc r3,r3,r1
:0209C44C E0B00000 adcs r0,r0,r0
:0209C450 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C454 30433001 subcc r3,r3,r1
:0209C458 E0B00000 adcs r0,r0,r0
:0209C45C E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C460 30433001 subcc r3,r3,r1
:0209C464 E0B00000 adcs r0,r0,r0
:0209C468 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C46C 30433001 subcc r3,r3,r1
:0209C470 E0B00000 adcs r0,r0,r0
:0209C474 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C478 30433001 subcc r3,r3,r1
:0209C47C E0B00000 adcs r0,r0,r0
:0209C480 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C484 30433001 subcc r3,r3,r1
:0209C488 E0B00000 adcs r0,r0,r0
:0209C48C E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C490 30433001 subcc r3,r3,r1
:0209C494 E0B00000 adcs r0,r0,r0
:0209C498 E0B13083 adcs r3,r1,r3,lsl #0x1
:0209C49C 30433001 subcc r3,r3,r1
:0209C4A0 E0B00000 adcs r0,r0,r0
:0209C4A4 E1A01003 mov r1,r3
:0209C4A8 E12FFF1E bx r14
```

The gen 4/5 divmod uses roughly 47-53 instructions on average and roughly 50-55 cycles total. For both division and modulus together. Each of those adcs and subcc instructions is only 1 cycle vs. the 3 for each branch/loop in gen 3. It also never loops, cutting out expensive branching. I'm of the opinion that this is an unrolled loop with a switch statement in front for proper setup and is quite likely custom assembly written by someone at Gamefreak. It's extremely efficient, possibly because the one in gen 3 was so bad.

So now we know that the functions to create test PIDs in gen 3 was extremely poor in terms of speed. We also know how Method H works and why it causes so much slowdown.(slow calculation function) So knowing all of that, how does this relate to methods 2/3/4, etc? It isn't fast enough to always finish before video rendering functions(interrupts, really) break up the PID building function.

------

The GBA has some video functions that run 60x/second. They clear the screen, draw the screen, render video, etc. They are also interrupts and can run at any time if the GBA needs to.

One is called VBlank. Wikipedia defines VBlank as "The vertical blanking interval (VBI), also known as the vertical interval or VBLANK, is the time difference between the last line of one frame or field of a raster display, and the beginning of the first line of the next frame." Basically, it's an interval of time when nothing is drawn to the screen, though functiuons can continue to run. It isn't a thing, just a poeriod of time. In fact, the RNG runs once per VBlank interrupt period as part of the VBlank callback function. This means that the RNG runs(needlessly) 60x/second, not just when it is needed.

VCOUNT is an important I/O register that keeps track of the current vertical line that is being drawn to render the screen. The GBA's LCD screen is 240px wide by 160px high, so VCOUNT would be counting 160 lines from 0-159. Once VCOUNT is filled up, the screen must be cleared to render the next frame.

Let's have a look at a diagram:

This is a chart of the LCD and the blanking intervals. As we can see the GBA is 240x160, but there looks to be extra room around the screen to the right and below. That is the period of time when VBlank/HBlank are running. Lines are still being drawn, they just aren't being rendered onscreen. As we can see in the red-boxed items, the normal number of lines is 160(thus what VCOUNT normally counts to), but there are 68 extra horizontal lines being drawn that aren't showing up on the screen because nothing is being written to it. During this 4.994 milliseconds, the VBlank function is running. The RNG advances once, as well. Since the screen is 160px tall and 68 extra lines are being drawn, we can conclude that the total number of horizontal lines being drawn per vertical interval is 228 and it occurs in 16.743ms(11.749 + 4.994)

Now, as I said, VBlank is an interrupt. That means that it can run at any time. What triggers it, though? VCOUNT is the sort of "monitor" for the horizontal lines being drawn vertically. When it hits 0xA0(160), that means the screen is full and VBlank must occur to clear the screen for the next frame of video. So, VCOUNT hits 160, the interrupt handler fires, VBlank runs no matter what to keep everything onscreen moving fluidly, and then it bounces back to what it was doing. ,This means that the game has 11.749ms to fully create a pokemon using those extremely slow PID creation functions and all the modulus calculations. If that doesn't happen, VBlank will occur and the RNG will advance once and throw off the pokemon being made.

So now we know about the VBlank period and VCOUNT and interrupts and the IRQ handler, etc. Let's go ahead and tie this all together.

If you look in a debugger(VBA-SDL-H, VBA-M, or No$GBA) and keep up, you'll notice that during the PID creation function where the game is wasting huge numbers of cycles, the VBlank interrupt will occasionally fire and advance the RNG by 1. If you notice that happening, stop the debugger and have a look at the VCOUNT register and you will see that it is always 0xA0). So then, what precisely is happening?

Due to the slow speed of the function used for basically all of Method H(mainly the PID creation, though- little numbers into big numbers is very rough on it), VCOUNT fills up and thus, another video frame must be rendered. Before the new frame is rendered, the VBlank interrupt fires and wipes the screen, **also causing the RNG to advance.** Occasionally, VCOUNT will fill up as the final PID is being built and will cause an advancement between PID halves or between PID and IVs or IV halves. This is how the other methods are created. If the pokemon creation function isn't able to finish in 11.749ms(provided it has the full interval to work with), then the RNG will advance with VBlank, causing one of the other methods.

In conclusion, we can say that the other methods(2-4, at least) are caused by Gamefreak's own poor programming practice and technique. The Application Note I referred to(#34) is from roughly 1998, so there is no reason to not have read it and implemented it ASAP. It is clear that gamefreak was aware of the issue, as gen 4 and 5 have an extremely fast(probably custom) div/mod algorithm implemented and it is 8-10 times as fast.

For reference

-------------

The offsets for Method H came from my work here:

http://projectpokemon.org/wiki/Notable_Breakpoints

GBATek is still the best and biggest source of info for the GBA and NDS:

http://pokemon.thundaga.com/research/gbatek.htm

The diagram and other great info came from romhacking.net's GBA programming manual:

http://www.romhacking.net/documents/228/

GBADev and its forums is a great source of dev info(and general info) for both the GBA and NDS:

http://gbadev.org/, http://forum.gbadev.org/

e:

How could I forget the ARM Application Note set?

http://www.nalanda.nitc.ac.in/industry/appnotes/arm/appsnotes/index.htm

(and not "detailed formula") to show the number of cycles the current instruction uses, you can get a more accurate count. long story short, i was

the gen 3 modulus function seems to use about 750(!!) cycles per run, while the gen 4/5 divmod uses 55 or so. so the gen 3 mod function was taking even more time than i thought, which just makes my point even stronger.

can someone name a place where the rng advances double-time outside of battle? i'd like to see if it's the same for that and (preferably) what exactly causes it.

can someone name a place where the rng advances double-time outside of battle? i'd like to see if it's the same for that and (preferably) what exactly causes it.

Apparently, Cerulean Cave is a "noisy" area as long as you don't load your game from inside the cave. I'm not 100% sure so it's worth double checking.

i should also probably mention that those walls of text above are also responsible for split breeding spreads.

also, the pokemon gba games were gamefreak's first foray into arm/programming for the arm cpu series, so i guess it's sort of understandable that it didn't come out great?

also, the pokemon gba games were gamefreak's first foray into arm/programming for the arm cpu series, so i guess it's sort of understandable that it didn't come out great?

On a less related note, I'm having trouble getting my seed from FRLG Seedfinder, and I was wondering if anyone could either point me towards a written guide for it (if there is one) or give me a set of steps to go through to get accurate results. The problem I'm having is that the seed output that Seedfinder gives me doesn't fit with the spreads RNG reporter says I should be getting and the results I'm actually getting on. Could someone maybe pm me about this? (I don't wanna hijack the thread.)

http://www.peter-teichmann.de/adiv1e.html

that's their divmod routine, in arm, just without the switch and written for strongARM, not arm7tdmi or arm946-es.

Code:

```
#include <nds.h>
#include <stdio.h>
#include <timers.h>
#define REG_GXSTAT (*(vu32*)0x04000600)
#define REG_T0 (*(vu16*)0x04000100)
#define REG_T1 (*(vu16*)0x04000104)
#define REG_T2 (*(vu16*)0x04000108)
#define REG_T3 (*(vu16*)0x0400010C)
volatile int frame = 0;
typedef unsigned short u16_t;
typedef unsigned int u32_t;
typedef unsigned long long u64_t;
u32_t rand64();
u64_t mul64(u64_t num1, u64_t num2);
u16_t rand32();
u64_t seed = 0;
u32_t seed32 = 0;
[b][i]
//---------------------------------------------------------------------------------
void Vblank() {
//---------------------------------------------------------------------------------
frame++;
rand32();
rand64();
}
[/b][/i]
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
lcdSwap();
irqSet(IRQ_VBLANK, Vblank);
consoleDemoInit();
int i = rand() % 4;
switch(i)
{
case 0:
TIMER_CR(0) = TIMER_ENABLE | TIMER_DIV_1;
break;
case 1:
TIMER_CR(1) = TIMER_ENABLE | TIMER_DIV_64;
break;
case 2:
TIMER_CR(2) = TIMER_ENABLE | TIMER_DIV_256;
break;
case 3:
TIMER_CR(3) = TIMER_ENABLE | TIMER_DIV_1024;
}
iprintf(" Test\n\n");
//iprintf(" %X \n", t0);
u32_t gx = REG_GXSTAT + rand();
seed = (u64_t)gx;
while(1) {
//timerStop(i);
u16_t lc32 = rand32();
u32_t lc64 = rand64();
iprintf("\x1b[10;0HFrame: %u", frame);
iprintf("\x1b[12;0H64-bit: %16llX", seed);
iprintf("\x1b[14;0H64-bit return: %08X", lc64);
iprintf("\x1b[16;0H32-bit: %08X", seed32);
iprintf("\x1b[18;0H32-bit return: %04X", lc32);
swiWaitForVBlank();
}
return 0;
}
u32_t rand64()
{
const u64_t a = 0x5d588b656c078965;
const u64_t c = 0x0000000000269ec3;
seed = mul64(seed, a) + c;
return (u32_t)(seed >> 32);
}
u64_t mul64(u64_t num1, u64_t num2)
{
u64_t result = (num1 * num2);
return result;
}
u16_t rand32()
{
const u32_t a = 0x41C64E6D;
const u32_t c = 0x00006073;
seed32 = (a * seed32) + c;
return (u16_t)(seed32 >> 16);
}
```

http://pokemon.thundaga.com/research/apps/vblank.nds

(note for mods: this is a program that i wrote and compiled using a free toolchain. no illegal/confidential applications were used to build this rom image. feel free to pm me for further clarification.)

now, if you run it, you'll see a frame counter, and both rngs running along with output to cut them in half like gamefreak does. what you're seeing here is vblank running at 60fps(since it's clearing the screen to let the next frame of video be drawn) and every time it runs, the rng advances once. this is exactly what gamefreak did and how the rng advances quickly in gen 3.

- Status
- Not open for further replies.