WiiRd forum

Wii & Gamecube Hacking => Wii Game hacking help => Topic started by: Almas on January 06, 2009, 10:12:52 PM

Title: ASM Branch (C2) code troubles
Post by: Almas on January 06, 2009, 10:12:52 PM
Okay, I've been trying to play with ASM for a little while and it's not playing nice. I feel I'm probably making a grievous error somewhere, but I'm not quite sure what it is, so I'd appreciate some help. I've been using the ASM to WiiRD converter found on this site. Essentially, the code in the game is something like this:

li f1, -31435(r3)   // loads the value stored at [r3-31435] into f1

My simple (but apparently overambitious) plan is to change the value stored at f1 to a multiple of its original self instead of what it's meant to be. However, I'm not making any progress with my attempts and I'm not quite sure what I'm doing wrong. For example, as a test I tried:

<start of branch>
li f1, -31435(r3)
srwi f1, f1, 1  // bitshift right once (0x01 produces the same code)
<end of branch>

However, the game froze immediately.

My only suspicion as to what the problem is is that it's something to do with trying to modify float registers, but I'm not really certain. My ideal goal is to be able to multiply by a floating point below one, but I'd be happy to settle for the sum of inverse powers of two (using many bitshifts).

Thanks for any assistance.
Title: Re: ASM Branch (C2) code troubles
Post by: paprika_killer on January 06, 2009, 10:31:59 PM
modifiing float registers is fine, but first of all you need to make sure your C2 ends with the commando you replaced with the branch.

for example is the adress 80B12345 contains the command stw r1, 4(r3) this has to be the last command in your branch, or nop if you need to fill the line.

also, li is used incorrectly try lfs instead
Title: Re: ASM Branch (C2) code troubles
Post by: Almas on January 06, 2009, 10:35:50 PM
The game uses li in that context.

And why does the C2 have to END with that command? I suppose I can just patch the next line to do the things I want to do to f1, I'm just curious.
Title: Re: ASM Branch (C2) code troubles
Post by: Igglyboo on January 06, 2009, 11:47:24 PM
You should end the code with li f1, -31435(r3), not start with that.
Title: Re: ASM Branch (C2) code troubles
Post by: Y.S. on January 07, 2009, 12:08:07 AM

Quote from: Almas on January 06, 2009, 10:12:52 PM
<start of branch>
li f1, -31435(r3)
srwi f1, f1, 1  // bitshift right once (0x01 produces the same code)
<end of branch>

li and srwi instructions can't handle float registers, and
you can't multiply float registers by bitshift.


In this case, the code would be like this:

lfs f1,-31435(r3)
lfs fx,0(r2)
fmuls f1,fx,f1

04YYYYYY ZZZZZZZZ

fx can be any float register which will be overwritten.
YYYYYY = address stored in r2.
ZZZZZZZZ = Floating point number
1.0 = 3F800000
2.0 = 40000000
4.0 = 40800000
0.5 = 3F000000
0.25 = 3E800000

Title: Re: ASM Branch (C2) code troubles
Post by: Almas on January 07, 2009, 06:43:00 PM
Aha, I see. I managed to get it working with that help, thank you =).

That said, the code affects far more than I ever thought it would - in an attempt to change one velocity i've seemingly changed almost all of them!

EDIT: I don't suppose anyone could explain to me the limitations on the values to be stored in places? I've figured out I can load 32bit values by first loading a 16-bit shifted value then adding the other half, but it's quite confusing why I should have to. Also, is there are list of the actual mnemonics the wii uses? The lists online seem to vary in content and exclude certain commands.

The current code for those who care - I put the code in on the next line after the game's loading of f1. Y'all were right, it was lfs used in game, I must have made a mistake in remembering. Silly me. Anyway:

lis r4, 0x8000 \\ Sets r4 = 8000000
lfs f31,6204(r4) \\ Sets f31 = [8000183C] (grE, for lack of a better place which will be used in the final code - I have previously written an appropriate value to gecko register)
fmuls f1, f31, f1 \\ f1=f1*f31
blr \\ back to the LR
Title: Re: ASM Branch (C2) code troubles
Post by: paprika_killer on January 07, 2009, 07:07:05 PM
what does blr do?
and why not just li r4, 0x8000183C  ?
Title: Re: ASM Branch (C2) code troubles
Post by: Romaap on January 07, 2009, 07:14:06 PM
blr:

Instruction: blr  target_addr
Description: Branch to LR (Link Register)
Explanation of operation: Branch and link to target_addr
Title: Re: ASM Branch (C2) code troubles
Post by: Almas on January 07, 2009, 07:20:45 PM
Quote from: paprika_killer on January 07, 2009, 07:07:05 PM
what does blr do?
and why not just li r4, 0x8000183C  ?

Error: operand out of range (0x8000183c is not between 0xffff8000 and 0x00007fff)
Title: Re: ASM Branch (C2) code troubles
Post by: paprika_killer on January 07, 2009, 07:31:53 PM
wierd error
Title: Re: ASM Branch (C2) code troubles
Post by: Romaap on January 07, 2009, 07:41:11 PM
thats not an error, it's the way li works.
Title: Re: ASM Branch (C2) code troubles
Post by: paprika_killer on January 07, 2009, 08:10:00 PM
li is a 16 bit code?
Title: Re: ASM Branch (C2) code troubles
Post by: Almas on January 07, 2009, 08:22:00 PM
Yeah, it seems you can only load 16 bits. If you want to get all 32 you have to lis then addi.

I have to figure out how to proceed now (I loosely understand how my glitch is caused, so I can work around it). However, I'm a bit confused by the compare mnemonics. I figure I'm either going to have to compare the value of a register to an immediate (If I can find that certain in-game actions which all use the code I've changed each cause specific changes to another register), or compare two registers. How do I tell the game what to do depending on the result of the comparison? How does the compare thing work, anyway?

I somewhat suspect I'm in over my head.
Title: Re: ASM Branch (C2) code troubles
Post by: paprika_killer on January 07, 2009, 09:33:45 PM
you use the brach instruction (b..)

like beq value means break if equal (or not equal not sure but you can look that up)

so if you did:

cpwi r1,r2
beq 0x08 (one line of code)
addi r2, 8

would only add 8 to r2 if it was not equal to r1
Title: Re: ASM Branch (C2) code troubles
Post by: brkirch on January 07, 2009, 10:18:24 PM
Quote from: paprika_killer on January 07, 2009, 07:07:05 PM
what does blr do?
and why not just li r4, 0x8000183C  ?
blr sets the CPU's internal PC (program counter, this tells the CPU where in memory to execute code) to the value in the LR (link register).  As for the li instruction it only takes 16-bit signed values.  If you want to use a 32-bit value, you need to first use lis for the upper 16-bits, then use addi or ori to set the lower 16-bits (I would recommend using ori, as it takes unsigned 16-bit values).

Quote from: Almas on January 07, 2009, 06:43:00 PM
Aha, I see. I managed to get it working with that help, thank you =).

That said, the code affects far more than I ever thought it would - in an attempt to change one velocity i've seemingly changed almost all of them!
Some games reuse a lot of code - this means that if you alter game code to change one thing, it might change everything else too.

Quote from: Almas on January 07, 2009, 06:43:00 PM
EDIT: I don't suppose anyone could explain to me the limitations on the values to be stored in places? I've figured out I can load 32bit values by first loading a 16-bit shifted value then adding the other half, but it's quite confusing why I should have to. Also, is there are list of the actual mnemonics the wii uses? The lists online seem to vary in content and exclude certain commands.

The current code for those who care - I put the code in on the next line after the game's loading of f1. Y'all were right, it was lfs used in game, I must have made a mistake in remembering. Silly me. Anyway:

lis r4, 0x8000 \\ Sets r4 = 8000000
lfs f31,6204(r4) \\ Sets f31 = [8000183C] (grE, for lack of a better place which will be used in the final code - I have previously written an appropriate value to gecko register)
fmuls f1, f31, f1 \\ f1=f1*f31
blr \\ back to the LR
Instructions are always 32-bits in length on PPC processors, so there is no way for a single instruction to hold 32-bits in addition to its opcode.  You may just want to look through some of the links posted here:
http://wiird.l0nk.org/forum/index.php?topic=2356.msg24468#msg24468 (http://wiird.l0nk.org/forum/index.php?topic=2356.msg24468#msg24468)
In the same topic I (try to) explain how to determine what registers can be used.

Quote from: Almas on January 07, 2009, 08:22:00 PM
Yeah, it seems you can only load 16 bits. If you want to get all 32 you have to lis then addi.

I have to figure out how to proceed now (I loosely understand how my glitch is caused, so I can work around it). However, I'm a bit confused by the compare mnemonics. I figure I'm either going to have to compare the value of a register to an immediate (If I can find that certain in-game actions which all use the code I've changed each cause specific changes to another register), or compare two registers. How do I tell the game what to do depending on the result of the comparison? How does the compare thing work, anyway?

I somewhat suspect I'm in over my head.
The CR register holds the results of cmp instructions and integer operations instructions that end with '.'  There is documentation about what is stored in CR in this pdf file (http://www.freescale.com/files/product/doc/MPCFPE32B.pdf) but you may have to search through it a while to find it.  To summarize though, CR can hold up to 8 different comparison results, and which part of CR to use is specified by CR0, CR1, ... , CR7 (CR0 is the default).  There are 4 bits in each CR slot, which have the following meanings:
bit 0 - Negative or less than (set when result is negative for integer operations ending with '.', or less than for cmp instructions when the first operand is less than the second)
bit 1 - Positive or greater than (set when result is positive for integer operations ending with '.', or greater than for cmp instructions when the first operand is greater than the second)
bit 2 - Zero or equal to (set when result is zero for integer operations ending with '.', or equal to for cmp instructions when the first operand is equal to the second)
bit 3 - Summary overflow, set when an integer operation results in an overflow

You need to then use a branch conditional to branch (skip code) if a bit is or isn't set.  For example, use beq to branch if the equal to CR bit is set, bne to branch if the equal to CR bit is not set, bgt to branch if the greater than CR bit is set, and blt to branch if the less than CR bit is set.

Quote from: paprika_killer on January 07, 2009, 09:33:45 PM
you use the brach instruction (b..)

like beq value means break if equal (or not equal not sure but you can look that up)

so if you did:

cpwi r1,r2
beq 0x08 (one line of code)
addi r2, 8

would only add 8 to r2 if it was not equal to r1
Almost right, but it is branch if equal, and let me fix up your code a bit:
cmpw r1,r2
beq 0x08
addi r2,r2,8
Title: Re: ASM Branch (C2) code troubles
Post by: Almas on January 08, 2009, 05:57:34 PM
Thanks so much for your help - managed to complete the code at long last and also get some understanding behind it!

One of the glitches I had to work around was with a bne - I thought it meant you would skip the next X bits but instead you skip TO X bits ahead. Caused some bizarre crashes while I tried to figure out what was going on.
EDIT: The final product for those interested:

Short Hop Height/Fast Fall Speed Multiplier [Super Smash Bros: Brawl, American]
045A9304 XXXXXXXX
045A9308 YYYYYYYY
C285765C 00000006
3FC0805A 3BDE7304
2C002F20 4082000C
C3FE2000 EC3F0072
2C002F5C 4082000C
C3FE2004 EC3F0072
4E800020 00000000


Where the XXXXXXXX is a float to multiply normal shorthop height by, and YYYYYYYY the value to multiply fastfall speed by.

Thanks again for all your help.