Dolphin, the GameCube and Wii emulator - Forums

Full Version: Setting a breakpoint BEFORE launching game?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3
(03-06-2022, 05:15 AM)Modception Wrote: [ -> ]This is a crazy question, but what happens if you branch back to the first instruction the game is at when it loads (pause on start).

It seems to work!   This code is working for the USA version of Wave Race:
 
Code:
// patch 480i mode
2834142e 00000280  // if 8034142e = 0280 (640 viWidth)
0634142e 00000002  // write 2 bytes to 8034142e:
02c00000 00000000  // 02c0 (704 viWidth)

// patch 480p mode
2834146a 00000280  // if 8034146a = 0280 (640 viWidth)
0634146a 00000002  // write 2 bytes to 8034146a:
02c00000 00000000  // 02c0 (704 viWidth)

// reset system
C0000000 00000002  // do 2 lines of ASM:
48000DA0 60000000  // branch ahead dA0 bytes to 80003100 (game's entry point)
4E800020 00000000  // "return" required by gecko

However the code assumes gecko will insert the ASM at da0 bytes before the game's entry point -- will this be true on all systems?


(03-06-2022, 05:15 AM)Modception Wrote: [ -> ]Also, I think the correct way to do a code branch (if there even is one) is to do a normal branch over a blr command, then the next blr should send you to the location the replaced blr pointed to.

Unless the game does a bl in between & the next blr will go there instead!

Perhaps we need to insert an address into the call stack with something like:

Code:
stwu    sp, -0x0080 (sp)

I did manage to patch a function so that when it did its final blr, the call stack according to Dolphin was identical to no patches, but it still ended up in some weird memory section where it was doing an infinite loop of nops. 


(03-06-2022, 05:15 AM)Modception Wrote: [ -> ]I feel like the people who do aspect ratio fixes should know how to do this.

Yeah I'm looking at Mario Sunshine's 16:9 code and it does contain a few branches, but I think it may only be branching within the function being patched.  Branching outside to other functions may be a different ballgame.

Thanks again for the reset tip -- this should come in handy for other games as well.
On Wii hardware (Nintendont) the memory writes don't work unless I remove the if statement before them.  No idea why as the if statement is working for other gecko codes on Nintendont.   According to Dolphin, gecko is executing its code handler on every frame.  Presumably this is only for certain gecko codes otherwise branching to entry point would result in an infinite loop if done every frame.
(03-05-2022, 04:38 AM)pneumatic Wrote: [ -> ]After spending some time on this, I'm not sure it's possible to arbitrarily jump to other functions without preserving the call stack and link register, and possibly other registers too.   Otherwise it seems I just end up in an infinite loop or in wrong memory area due to code executing in the wrong order which the compiler didn't design it to do.

Seems this may be possible after all -- Guide For Calling Functions in ASM Codes -- MarioKartWii.com
(03-06-2022, 06:45 PM)pneumatic Wrote: [ -> ]According to Dolphin, gecko is executing its code handler on every frame.  Presumably this is only for certain gecko codes otherwise branching to entry point would result in an infinite loop if done every frame.


It seems the explanation is because I didn't put halfway terminators so my code is actually equivalent to:

Code:
if 8034142e == 0280
{
    write 02c0 to 8034142e
    
    if 8034146a == 0280
    {
        write 02c0 to 8034146a
        reset game
    }
}


So the reset only occurs if both ifs return true, then after the game is reset, they no longer return true so no infinite reboot loop -- handy.

On Wii hardware for some reason the ifs are always returning false, so it never gets a chance to patch anything.  After removing the ifs, the reboot occurs, but goes into infinite loop.

Noticed in Dolphin that Gecko's 32-bit if statements and RAM writes are being automatically aligned to the nearest 32-bit-divisible memory chunk, resulting in those statements being offset by a few bytes if they don't happen to align, causing the code to fail.

Also I need to adjust XOrigin after patching VIWidth otherwise the frame will be slightly off center.
This strategy seems to be working on Dolphin and Wii console:

Code:
if myVar == 0
{
    myVar = 1    // prevent infinite reset loop

    write new viWidth & xOrigin to GXRenderModeObjs

    do ASM
    {
        reset game
    }
}

Gecko of the above:

Code:
28002408 00000000        // if 80002408 == 0000 (if myVar == 0)

    00002408 00000001        // myVar = 1

    0034142f 000000c0        // 8034142e = 704 (480i viWidth)
    0034142b 00000008        // 8034142b = 8 (480i xOrigin: 720-704/2=8)
    0034146b 000000c0        // 8034146a = 704 (480p viWidth)
    00341467 00000008        // 80341467 = 8 (480p xOrigin: 720-704/2=8)

    C0000000 00000003        // do 3 lines of ASM:

        3D808000 618C3100        // r12 = 80003100 (game's entry point)
        7D8803A6 4E800020        // link register = r12, branch to link register
        60000000 00000000        // end of ASM

The reason I'm using a custom myVar is because Gecko's if statements don't seem to be reliable for this game -- with Dolphin the 32-bit ifs and RAM writes are misaligned by 2 bytes, and on Wii the 16 & 32-bit ifs aren't working at all.   I chose 80002408 for myVar as it's in an area of seemingly unused memory a few lines below where Gecko puts its codes.   If the game happened to write a 0000 there, it would cause the game to reboot!
Wow, good job! iirc C0 codes are run-once ASM instructions for gecko.
Gecko has extra space to hold values, starting at 800001804. If you know that won't be used by other codes, then that's a safe place to put a value. https://gamehacking.org/faqs/wiicodetypes.html

I'm not sure, but the xenoblade 60fps code says A8000000 00000000 is run once and then it ends the code with E0000000 80008000, which I think ends the run once. So you may be able to skip the whole value and condition stuff and just wrap the code in a run once block with those lines at the top and bottom.
(03-07-2022, 05:39 AM)Modception Wrote: [ -> ]iirc C0 codes are run-once ASM instructions for gecko.

That's what I thought too but after putting a breakpoint on the gecko codes it seems they are executed every frame unless we do something to avoid that specifically, such as the A8 code you mentioned.

When I think about that it does seem to make sense because it has to ensure the values being patched are staying patched for the duration of the game.    

The A8 code appears to "increase a counter by 1 if current execution status is true, else reset counter to 0" .

So the code A8000000 00000000 should mean the counter is initially set to 0, and is compared to 0 , which evaluates to true, so the lines below it are executed -- until a terminator is encountered, such as E0000000 80008000 (end of entire code) or E0000000 00000000 (end of this block in the code).  

The A8 code then increments the counter by 1 so on the next frame it executes again but now it's comparing 1 to 0 which evaluates false so the lines below it aren't executed.
The A8 code seems to works fine on Dolphin and Wii, so I'll use that instead -- thanks for the tip.  

I've added codes for Wave Race and Burnout games to the wiki.   I'll probably be doing more of them as I work my way through my Gamecube library and find more titles needing a stretch.

I am still disappointed to find the "if equal" codes beginning with 20 and 28 are not reliable on the Wii console.  For some reason they are returning false with these games, causing the code to fail.  Removing the "if equal" and just writing the patched values works fine, although it's a bit unsafe as I only want it to write the values if their memory happens to contain a video mode object, since the game might use that memory space for other things at other points in the game, or the user might be using a different region of the game which shouldn't be patched and would corrupt the game if it were.  

There really is something wrong with those if statements on Wii console!  I suspect it's an alignment issue where Gecko is rounding the address to the nearest 16/32 bit divisible chunk.  I tried offsetting the address of the if statement by +/- 1,2,3,4 bytes without success.   For writes I can seemingly avoid it by using the 00 code (writes a single byte) but there is no single-byte if statement.

Oh well, at least the codes are working that's the main thing.
Was it not possible to modify the widescreen codes to get the ratios?

If you need to align the code you would set it to _C and compare CDEF. Is CD constant so that you can try that? Then write to EF01 like normal. Also make sure you always endif everything.
(03-12-2022, 08:47 AM)Modception Wrote: [ -> ]Was it not possible to modify the widescreen codes to get the ratios?

It's certainly possible, but that widescreen code for Wave Race appears to only work during actual racing and not in replays & menus.  Plus I'm already familiar with GXRenderModeObj & VIConfigure so it's easier for me to patch any game.


(03-12-2022, 08:47 AM)Modception Wrote: [ -> ]If you need to align the code you would set it to _C and compare CDEF. Is CD constant so that you can try that? Then write to EF01 like normal.

Sorry I'm not following -- what are CDEF?
Pages: 1 2 3