WiiRd forum

Wii & Gamecube Hacking => Wii Game hacking help => Topic started by: AlexWong on August 07, 2010, 10:35:49 AM

Title: How to convert integer value to float value?
Post by: AlexWong on August 07, 2010, 10:35:49 AM
MIPS 32bits cpu has the instruction "cvt.s.w fD, fS" (such like PSP used R4000 ASM) can convert integer value to float value. I found that PowerPC750 is also a 32bits CPU but the unique instruction "fcfid fD, fS" needs 64bits integer registers. Only "fctiw fD, fS" or "fctiwz fD, fS" need 32bits integer registers. Is there any other method to convert integer value to float value on Wii? ???
Title: Re: How to convert integer value to float value?
Post by: dcx2 on August 07, 2010, 07:39:03 PM
It's a pretty convoluted process to do an int->float cast.  You basically have to build a 64-bit double-precision float; sign, exponent, and mantissa.  And then you have to subtract it from a "magic double".  Then you'll have the (single-precision!) float that you're looking for.

http://wall.riscom.net/books/proc/ppc/cwg/code3.html

Figure 3-52

32-Bit Implementation
   # FR2 = 0x4330000080000000
   addis    R0,R0,0x4330    # R0 = 0x43300000
   stw    R0,disp(R1)    # store upper half
   xoris    R3,R3,0x8000    # flip sign bit
   stw    R3,disp+4(R1)    # store lower half
   lfd    FR1,disp(R1)    # float load double of value
   fsub    FR1,FR1,FR2    # subtract 0x4330000080000000


In this case, they are assuming that FR2 contains the bit pattern 0x4330000080000000.  Note this is a 64-bit value; the FRs in the PPC are 64-bit.  Most games have this magic float stored in constants that are accessed with the Small Data Anchor, r2.  If you can find that for your game, rock on!  For instance, Resident Evil 4 stores the Magic Float at -27352(r2).

Otherwise, you'll need to create the Magic Float somewhere, probably on the stack, or maybe even in the C2 code itself.

The first line of the example is building the sign, exponent, and the first 20 bits of the mantissa.  The second line stores this first half.  The third line flips the bit (it matches up with the 8 in the middle of the Magic Float)  The fourth line line stores this second half.  The fifth line loads the double we just build.  The sixth line then "normalizes" the float we built by subtracting the Magic Float from it.
Title: Re: How to convert integer value to float value?
Post by: AlexWong on August 07, 2010, 11:43:27 PM
Oh maybe you misunderstood my question. I meant how to convert integer value to float value (such as convert 0x00000064 to 0x42C80000).
Title: Re: How to convert integer value to float value?
Post by: dcx2 on August 08, 2010, 01:49:45 AM
No, I did not misunderstand you.  You want the value 1 to turn into 0x3F800000.  2 into 0x40000000.  You can't just use a constant (or you could code it in directly), because you need to convert a value in memory or in a register.

32-bit PowerPC processors don't have any easy way to do an integer -> float cast.  The way I described above is how games do it.  I can show you game logs of Super Mario Galaxy 2 and Resident Evil 4 if you don't believe me.
Title: Re: How to convert integer value to float value?
Post by: AlexWong on August 08, 2010, 12:50:44 PM
I still don't understand. :confused: Could you show me the sample of the asm instructions in RE4, please?
Title: Re: How to convert integer value to float value?
Post by: dcx2 on August 08, 2010, 06:31:41 PM
It's complicated.  It helps to know what a float looks like in memory.  Google sign exponent mantissa and you should get some good results.

Here's the example from RE4.  I have removed interleaved instructions that are not relevant to the example.  This example takes the integer value in r0 @ address 8009FF38, and puts it into the floating point register f2 @ address 8009FF4C.

---

8009FB18:  3C004330   lis   r0,17200      r0 = 81280048
...
8009FB20:  90010008   stw   r0,8(r1)      r0 = 43300000   r1 = 806A7FA8   [806A7FB0] = 00000000
...
8009FF34:  C8629528   lfd   f3,-27352(r2)   f3 = 4.2949673E+09   r2 = 80446B60   [80440088] = 4330000080000000
8009FF38:  6C008000   xoris   r0,r0,32768      r0 = 00000005   r0 = 00000005
...
8009FF40:  9001000C   stw   r0,12(r1)      r0 = 80000005   r1 = 806A7FA8   [806A7FB4] = 800002A3
...
8009FF48:  C8410008   lfd   f2,8(r1)      f2 = NaN   r1 = 806A7FA8   [806A7FB0] = 4330000080000005
8009FF4C:  EC421828   fsubs   f2,f2,f3      f2 = 4.5036E+15   f2 = 4.5036E+15   f3 = 4.5036E+15
8009FF50:  EC4100BC   fnmsubs   f2,f1,f2,f0   f2 = 5   f1 = 0.03   f2 = 5   f0 = 1

---

line B18 builds the first half of the converted double and puts it on the stack at 8(r1).  This contains the sign, exponent, and 20 bits of the mantissa.  It is always the same.
line F34 reads the Magic Float 4330000080000000 by using the small read-only data anchor r2.  This value will always be here for this game.  It's a constant.
line F38 takes the value that we want, which is in r0 = 5, and flips the highest bit, so that it's 80000005 (as can be seen in the log at F40).  This creates the second half of the converted double.
line F40 puts the second half of the converted double on the stack at 12(r1).  In combination with F34, this creates the full 64-bit representation of our converted double on the stack.
line F48 reads our converted double off the stack.  Notice the 64-bit operand.
line F4C normalizes our converted double by subtracting the Magic Float.

Just in case you don't believe that this process works, I included the next line from the Gecko.NET log.  It shows that f2 contains a 5 in floating point (the integer value which was originally in r0).  The Text View of Gecko.NET confirms that f2 contains the bit pattern 40A00000, which is a 32-bit single-precision 5.
Title: Re: How to convert integer value to float value?
Post by: AlexWong on August 09, 2010, 01:39:33 AM
4330000080000005=4503601774854149.00000000000000000000
4330000080000000=4503601774854144.00000000000000000000
4503601774854149.00000000000000000000-4503601774854144.00000000000000000000=5.00000000000000000000
I get it. Thank you very much. ^-^