WiiRd forum

Wii & Gamecube Hacking => Wii Game hacking help => Topic started by: Stuff on August 24, 2011, 02:19:59 AM

Title: ASM explanations...
Post by: Stuff on August 24, 2011, 02:19:59 AM
Hope it's alright to post this here. I want to use this thread much like I did with codetype explanation (http://"http://wiird.l0nk.org/forum/index.php/topic,8708.0.html").

So I'm a noob when it comes to this. I wasn't gonna post questions because I can figure this out myself. Or so I thought. >.> So I'm just gonna ask what an instruction does when the explanation in here (http://"http://www.pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/") or here (http://"http://class.ee.iastate.edu/cpre211/labs/quickrefPPC.html") aren't too obvious or I just can't find what I'm looking for there. Hope someone doesn't mind answering my questions.

Anyway, I'll start with branches. I thought I had them all figured out but then...I started using 'step into' on gecko.net and this happened about 3x in a row.

r0 != 36

8041553C:  2C000024   cmpwi   r0,36
80415540:  40820024   bne-   0x80415564

not the same cmpwi or branch, but each time I expected this to be "true" and gecko.net said "Not Taken" and the next step into didn't branch. >.>
This was in a loop that I stopped following because that happened. The next cycle it was "Taken" because r0 != 36 still. But why didn't it "take" it before? I think it might have something to do with the +/-. I read somewhere that the +/- is to eliminate it's prediction or something, but I never thought it was a big deal. But maybe it is a big deal. Maybe that's why it wasn't taking the argument when I expected it to be true. Maybe...idk.

----
[spoiler=an image to illustrate what I'm talking about](http://dl.dropbox.com/u/24514984/not%20taken.png)[/spoiler]
Title: Re: ASM explanations...
Post by: dcx2 on August 24, 2011, 02:44:48 AM
Remember that the registers are in hex, but the disassembly is in decimal.

As far as your image, it looks correct.  r0 = 0x2E = 46.  cmpwi r0,46 = equal bit of CR will be set.  Since equal bit is set, bne- will not be taken.

A cmp is actually a sub that doesn't store the result anywhere.  The CR is split into eight 4-bit fields.  These are cr0 thru cr7.  cr0 is usually assumed (all instructions ending with . will affect cr0 as if there was a cmpwi rX,0).  cmp and branch instructions can specify other cr fields; Gecko.NET doesn't support them and it will guess wrong.

The + and - are "static branch hints".  + means "probably taken", and - means "probably not taken".  In general, the compiler assumes all branches going backwards will be taken (i.e. it's a loop!).
Title: Re: ASM explanations...
Post by: Stuff on August 26, 2011, 02:50:10 AM
alright. So now I'm afraid of breaking something. This is the original instruction here.
817C5270:  4CC63182   crclr   6,6

I want to replace this line with stw   r9,1952(r18) because this would do the max heal monster. And then quickly restore the original instruction. BUT... it braches and a few instructions later:
8005C82C:  40860024   bne-   cr1,0x8005c850

I could just test the code out, but I just feel like this would cause some funky effects at some point even if I did test it..

I can of course do a C2 and just include both instructions in it, but then I have to end it with a nop so it can branch back. And that would end up being a 5 line code. I mean, it's still shorter than my code, but I was aiming at 4 lines.

----
nvm. The code didn't even work. weird that it doesn't though. It's the same idea I used for map attached to hud. The C3 by itself works, but I can't do a 04 after the if.
Title: Re: ASM explanations...
Post by: dcx2 on August 26, 2011, 03:08:07 AM
lol, you shouldn't really sweat one line so much.  Get a code working first, then optimize.  There were many versions of my RT4EAF encounter roller (http://wiird.l0nk.org/forum/index.php/topic,1840.msg70169.html#msg70169) and believe it or not, it's very tightly optimized, to the point where it's difficult to read the source.

crclr will clear a condition register field.  That looks like it clears cr6.  In terms of cr1, you'd want to look for something in the current function that was doing cmpwi cr1.  You can use the disasm search up for cr1 and you should find it.  Although I'm not sure why you're trying to hook that instruction instead of something else.
Title: Re: ASM explanations...
Post by: Stuff on August 26, 2011, 03:11:26 AM
Oh. cuz the instruction directly before it was 817C526C:  813207A4   lwz   r9,1956(r18). Kind of need that r9.

Regex search?
Title: Re: ASM explanations...
Post by: dcx2 on August 26, 2011, 04:32:55 AM
It's simple search by default, to use regex you must check about tab.

It usually helps to Copy Function into a spoiler any time you're trying to make a hook.  It sounds like that's the hook you actually want.
Title: Re: ASM explanations...
Post by: Stuff on August 26, 2011, 05:48:36 AM
Well I wanted to keep this thread for general asm questions like "wut is mflr". Just an example. I know what it is. I'll ask if it ever doesn't make sense.

Oh no... Now that I was gonna post the Copy Function, I got a different Read BP. And I just realized why. The old one was the MID XD. Not a good hook at all.

[spoiler]
CR:28200488  XER:00000000  CTR:801542D0 DSIS:00400000
DAR:9014C0E0 SRR0:8012ED08 SRR1:0000B032   LR:8012ED08
  r0:8012ED08   r1:807AD530   r2:8079DAA0   r3:00000002
  r4:80A2C398   r5:00000000   r6:00000000   r7:00000000
  r8:9014C282   r9:00000096  r10:80000000  r11:807AD560
r12:801542D0  r13:80798E20  r14:805A0000  r15:00000000
r16:00000001  r17:000000FF  r18:9014B940  r19:00000000
r20:00000000  r21:00000000  r22:0000000D  r23:00000000
r24:00000000  r25:00000000  r26:00000000  r27:801510C4
r28:0000C320  r29:00000000  r30:9014B940  r31:9014B940

8012ECF0:  9421FFE0   stwu   r1,-32(r1)
8012ECF4:  7C0802A6   mflr   r0
8012ECF8:  90010024   stw   r0,36(r1)
8012ECFC:  93E1001C   stw   r31,28(r1)
8012ED00:  7C7F1B78   mr   r31,r3
8012ED04:  4BFFFF71   bl   0x8012ec74
8012ED08:  801F07A0   lwz   r0,1952(r31) ##break
8012ED0C:  C86291C8   lfd   f3,-28216(r2)
8012ED10:  6C008000   xoris   r0,r0,32768
8012ED14:  9001000C   stw   r0,12(r1)
8012ED18:  3C604330   lis   r3,17200
8012ED1C:  90610008   stw   r3,8(r1)
8012ED20:  C8010008   lfd   f0,8(r1)
8012ED24:  EC401828   fsubs   f2,f0,f3
8012ED28:  801F07A4   lwz   r0,1956(r31) ##max hp is being load to r0. I want to stw after this. But something is gonna break >.>
8012ED2C:  6C008000   xoris   r0,r0,32768
8012ED30:  90010014   stw   r0,20(r1)
8012ED34:  90610010   stw   r3,16(r1)
8012ED38:  C8010010   lfd   f0,16(r1)
8012ED3C:  EC001828   fsubs   f0,f0,f3
8012ED40:  EC020024   fdivs   f0,f2,f0
8012ED44:  FC000840   fcmpo   cr0,f0,f1
8012ED48:  4C401382   cror   2,0,2
8012ED4C:  7C600026   mfcr   r3
8012ED50:  54631FFE   rlwinm   r3,r3,3,31,31
8012ED54:  83E1001C   lwz   r31,28(r1)
8012ED58:  80010024   lwz   r0,36(r1)
8012ED5C:  7C0803A6   mtlr   r0
8012ED60:  38210020   addi   r1,r1,32
8012ED64:  4E800020   blr   
[/spoiler]
But it's not good. I thought it might read the hp often, but it doesn't. I waited a little while to get this BP again. w/e. I think the max heal code is fine the way it is. Guess it's time to go back to "monsters don't see me".
Title: Re: ASM explanations...
Post by: Bully@Wiiplaza on August 26, 2011, 02:01:50 PM
C212ED28 00000002
3C00XXXX 6000XXXX
901F07A4 00000000

Set your amount by inserting the value into XXXX.
It stores it afterwards.
Title: Re: ASM explanations...
Post by: dcx2 on August 26, 2011, 02:42:22 PM
That function is doing some conversions to float.  Pay attention to this template.

8012ED08:  801F07A0   lwz   r0,1952(r31) ##break
8012ED0C:  C86291C8   lfd   f3,-28216(r2)
8012ED10:  6C008000   xoris   r0,r0,32768
8012ED14:  9001000C   stw   r0,12(r1)
8012ED18:  3C604330   lis   r3,17200
8012ED1C:  90610008   stw   r3,8(r1)
8012ED20:  C8010008   lfd   f0,8(r1)
8012ED24:  EC401828   fsubs   f2,f0,f3

Read this post for a breakdown of what is happening here.  http://wiird.l0nk.org/forum/index.php/topic,6593.msg56266.html#msg56266

Ultimately, when this is done, the value in r0 (current health, I believe) will be cast to a 32-bit single precision float.  The process is then repeated for the max health.  f0 = max health float, f2 = current health float.

8012ED40:  EC020024   fdivs   f0,f2,f0
8012ED44:  FC000840   fcmpo   cr0,f0,f1
8012ED48:  4C401382   cror   2,0,2
8012ED4C:  7C600026   mfcr   r3
8012ED50:  54631FFE   rlwinm   r3,r3,3,31,31

This is then doing f0 = current / max.  Then it's comparing the resulting quotient against f1, which is an argument passed in from the caller, and places the result of the compare in cr0.  It then ors cr2 and cr0 together; dunno why, because cr2 isn't used at all.  It then puts the cr result into r3 and masks off what I think is the equal bit of cr0 (I may be wrong, you should verify).  This is then returned to the caller via r3; 1 = equal, 0 = not equal.

---

hook   8012ED08:  801F07A0   lwz   r0,1952(r31)

lwz r0,1956(r31)   # read max health
stw r0,1952(r31)   # write to current health
# no need for original instruction; r0 has the right value in it already

C212ED08 00000002
801F07A4 901F07A0
60000000 00000000

---

EDIT: btw were you actually asking what mflr is doing?
Title: Re: ASM explanations...
Post by: Stuff on August 26, 2011, 03:55:40 PM
Quote from: dcx2 on August 26, 2011, 02:42:22 PM
hook   8012ED08:  801F07A0   lwz   r0,1952(r31)

lwz r0,1956(r31)   # read max health
stw r0,1952(r31)   # write to current health
# no need for original instruction; r0 has the right value in it already

C212ED08 00000002
801F07A4 901F07A0
60000000 00000000

---

EDIT: btw were you actually asking what mflr is doing?
>.> wut? r0:8012ED08. That's not someone's hp.
---
no that was just an example of what I meant to use this thread for.

And the code Bully Posted would only write XXXX to the hp. But that gave me an idea. Since it's only read sometimes, I could do "Monsters have Regen". I was thinking something like this:

li rX, 10 ##or 20 or something
divw rY, r0, rX ##why isn't there a divwi
add r0, r0, rY  ##current+quotient
stw r0, 1952(r31) ##healed 5-10 or something%
## do what needs to happen to not break the instructions. (happened with the box. was funny seeing so many exceptions caught. lol)

I just need to make sure this doesn't run every time the monster is hit. That would suck.

The float thing, I'll have to look into. That's extra new to me.
Title: Re: ASM explanations...
Post by: dcx2 on August 26, 2011, 04:47:07 PM
Quote from: Stuff on August 26, 2011, 03:55:40 PM
>.> wut? r0:8012ED08. That's not someone's hp.
Breakpoints occur before the instruction is executed.  You're seeing the old, stale value of r0.  You can right-click Show Mem to get a peek at the value that will be lwz'd.  (EDIT: you can also type in a new value and press Enter to do a 32-bit poke)  Or you could press Show Mem and go check it out in the memview tab.

Press Step Into and the instruction will execute, loading the monster's hp into r0.
Title: Re: ASM explanations...
Post by: Stuff on August 26, 2011, 05:22:24 PM
Oh. I was looking at it wrong. I was think that if you never lwz   r0,1952(r31), how could r0 have the correct value.  But I see it now. If your storing r0 to 1952(r31), why lwz it. :p Alright cool. Now that won't break anything. It still doesn't change the fact that it reads only sometimes. But I'll check to find when it reads later when I come back. That hook looks good for monsters have regen. lol.

Is it possible to divide or multiply by not an integer? Like r0*0.85. I don't think it is. And now I see there's no mulw. >.<
Title: Re: ASM explanations...
Post by: dcx2 on August 26, 2011, 11:39:32 PM
Quote from: Stuff on August 26, 2011, 05:22:24 PM
Is it possible to divide or multiply by not an integer? Like r0*0.85. I don't think it is. And now I see there's no mulw. >.<
It is possible to multiply by fixed-point integers, although the process isn't exactly straightforward.  Google fixed point for more info.

For instance, if you wanted to multiply r0 = 0x48 by 0.25, you would do something like this.  (I think - this is untested and it's been a while since I used fixed point integers, and fractional binary is not very straightforward)

lis r12, 0x4000   # All 32-bits are "behind" the decimal point, so r12 = 0b0.0100 0000 00... = 0.25
mulhw r0,r12,r0  # r0 = the upper 32-bits of r12 * r0

The product of two 32-bit numbers will be 64-bits.  If you consider r12 to be "behind the decimal point" then the upper 32-bits will be the product of the fixed point multiplication of r0 and r12.  The lower 32-bits would be the fractional remainder.
Title: Re: ASM explanations...
Post by: Stuff on August 27, 2011, 12:49:08 AM
>.> Yeah. I'll just uh...stick with this. r5 looks like it's free:

lwz r0, 1956(r31)   ## read max health
li r5, 20
divw r5, r0, r5 ##divide max health by 20. 5%
lwz r0, 1952(r31) ##read current health
add r0, r0, r5 ##healed by 5%
stw r0, 1952(r31) ##store new hp
:/ nop 00000000

Gonna see if this actually works now.
Title: Re: ASM explanations...
Post by: dcx2 on August 27, 2011, 01:32:39 AM
Quote from: Stuff on August 27, 2011, 12:49:08 AM
r5 looks like it's free:
What makes you believe that it's free?  I mean, it is free/safe.  But I have a feeling that you believe it is safe for the wrong reasons.

---

Also, if you don't mind dividing by powers of 2, this can be simplified.

lwz r12, 1956(r31)   # read max health
srawi r12,r12,4       # r12 = r12 / 16
lwz r0, 1952(r31)    # read current health
add r0, r0, r12       # healed by 5%
stw r0, 1952(r31) ##store new hp
Title: Re: ASM explanations...
Post by: Stuff on August 27, 2011, 03:21:36 AM
r5 = 0 and I don't see it being used in the near future. It'll probably li r5, X at some point if it gets used.
-----

Many thanks. That's way better. So I sent this code:
Monsters have Regen
C212ED08 00000003
819F07A4 7D8C2670
801F07A0 7C006214
901F07A0 00000000

The hp is read at an unusual rate. I can't understand what makes it read. Not even hitting them makes it read. It just does. Can't really see a pattern either. But it's whenever, often or not often. Another thing is that it'll heal past it's max hp XD. I was thinking of doing that Goto in the beginning of the code to skip some asm that would handle if it's greater than max hp. So 3 more lines.

66000001 00000000 #skip to C2
mr r0, r12 #move r12 to r0(max hp->current)
b 0x1C #go to the stw at the end
C212ED08 00000004
lwz r12, 1956(r31)   # read max health
srawi r0,r12,8       # r12 = r12 / 64? needed to make the heal smaller.
lwz r5, 1952(r31)    # read current health
add r0, r5, r0       # healed by 5%
cmp r0, r12 #compare new hp to max hp
bgt -0x1C #branch to skipped code if greater than
stw r0, 1952(r31) ##store new hp
00000000 #that 0 that needs to be at the end.

I have to think about the branches...PyiiASMH didn't want to do b 0x1C. Had to increase the divider. I couldn't keep up with the healing. I can srawi up to 32, right?
Title: Re: ASM explanations...
Post by: dcx2 on August 27, 2011, 05:26:03 AM
Quote from: Stuff on August 27, 2011, 03:21:36 AM
r5 = 0
Absolutely wrong.  0 does not mean safe.  This is a tutorial on register safety.

http://wiird.l0nk.org/forum/index.php/topic,6555.0.html

The short of it is: r12 is almost always safe. r11 is usually safe.  r10-r3 are of decreasing safety.  r14+ should never be considered safe without a thorough dependency analysis or a stack frame.

QuoteThe hp is read at an unusual rate. I can't understand what makes it read.

Well, it's comparing the percentage of health to some float argument in f1.  What's in f1?  What does it look like the caller wants to do with the return value?

QuoteAnother thing is that it'll heal past it's max hp XD. I was thinking of doing that Goto in the beginning of the code to skip some asm that would handle if it's greater than max hp. So 3 more lines.

66000001 00000000 #skip to C2
mr r0, r12 #move r12 to r0(max hp->current)
b 0x1C #go to the stw at the end
C212ED08 00000004
lwz r12, 1956(r31)   # read max health
srawi r0,r12,8       # r12 = r12 / 64? needed to make the heal smaller.
lwz r5, 1952(r31)    # read current health
add r0, r5, r0       # healed by 5%
cmp r0, r12 #compare new hp to max hp
bgt -0x1C #branch to skipped code if greater than
stw r0, 1952(r31) ##store new hp
00000000 #that 0 that needs to be at the end.

lol, I give you points for creativity.  You also knew that you couldn't just put ASM in the code list and that you had to protect it, in this case with a 66 Goto.  Although I'm not sure what lead you to believe you couldn't just put the ASM in with the C2 code...

Another thing you need to use are branch labels.  Branch labels automatically calculate the displacement operand necessary so you don't have to count bytes.  Yay not counting bytes!

"that 0" is actually allocating room for a back-branch.  The code handler will automatically write this back-branch with the correct address as part of carrying out the C2 code type.  That's why if there's not enough room, you need to add the nop.  Ironically, it doesn't have to be 0, you could make it anything you want because it will be over-written.

lwz r0, 1952(r31)    # read current health
lwz r12, 1956(r31)   # read max health
cmpw r0,r12          # is current >= max health?
bge- _END            # don't regen
srawi r12,r12,8       # r12 = r12 / 256
add r0, r12, r0       # healed by ~0.4%
stw r0, 1952(r31)  #store new hp
_END:

This has the side effect of healing them up to one regen over their max health.  Brimming full, so to speak.

Quote
I have to think about the branches...PyiiASMH didn't want to do b 0x1C. Had to increase the divider. I couldn't keep up with the healing. I can srawi up to 32, right?
Perhaps PyiiASMH expects everything that will exist in one single input.  The Encounter Roller I made is actually like 8 different C2 codes that all had to be entered at the same time so that they could access each other.  There's a degree of belly-rubbing and head-patting involved to make the assembler generate the code types.

It's a good idea to know the first ten powers of 2 by heart.  The next six are good to know, too.  2^8 = 256.  Therefore a right-shift by 8 bits will divide by 256.  2^6 = 64.  It can go up to 31, but at that point you would be dividing by 2^31 = 2,147,483,648.  (hint: calc shortcut for exponent is y; therefore 2y8 will give you 2^8 etc)
Title: Re: ASM explanations...
Post by: Stuff on August 27, 2011, 06:43:45 AM
Quote from: dcx2 on August 27, 2011, 05:26:03 AM
Quote from: Stuff on August 27, 2011, 03:21:36 AM
r5 = 0
Absolutely wrong.  0 does not mean safe.

Quote from: dcx2 on July 31, 2010, 07:51:42 PMMany people confuse 0 for safe, but that is not the case.  Safety cannot be determined from the value of a register; it could be 0 when you're looking at it and a different value later.
Ah. ya got me. >.<

It's a very nice guide. I'll refrence to it until I just know.
Quote from: Dude on July 31, 2010, 08:58:34 PMCould I download your brain? :p
Did you ever upload it? I need the link. XD

Quotelol, I give you points for creativity.  You also knew that you couldn't just put ASM in the code list and that you had to protect it, in this case with a 66 Goto.  Although I'm not sure what lead you to believe you couldn't just put the ASM in with the C2 code...

Another thing you need to use are branch labels.  Branch labels automatically calculate the displacement operand necessary so you don't have to count bytes.  Yay not counting bytes!
Well. I didn't think about branching to the end if >=. I was thinking if it's greater than the max, just rewrite the max. But if it's not, it would've went to the next instruction, which would've been my brach  anyway. The branch needed to be somewhere else. Branch labels are interesting. I know nothing about them. Can they be called _anything? Or was _END one of the many/few labels?

Quote
It's a good idea to know the first ten powers of 2 by heart.  The next six are good to know, too.  2^8 = 256.  Therefore a right-shift by 8 bits will divide by 256.  2^6 = 64.  It can go up to 31, but at that point you would be dividing by 2^31 = 2,147,483,648.  (hint: calc shortcut for exponent is y; therefore 2y8 will give you 2^8 etc)
Oh. I was looking at it wrong. >.< I thought 8^2.That was dumb. lol.

This was the code.

C212ED08 00000004
801F07A0 819F07A4
7C006000 40800010
7D8C4670 7C0C0214
901F07A0 00000000

It worked pretty nice. But that heal rate is so weird. it got annoying after a while. It was healing 10 hp each time. But at the rate it heals...Like, you can do a combo, sheathe your weapon, get hit, use a megapotion and nothing happens...and then out of nowhere, +10+10+10+10+10....+10+10..+10......>.>...<.<...:p..+10+10. XD. I'm gonna reduce it even more, but in the end, I might just do a +1/+2. It's a very nice code though. It's worthy of my gct.... When it gets tolerable.

The extra health wasn't a big deal. it went 9 hp over. 1 hit would get you back on track. And it's not like everyone uses MID >.>.
Title: Re: ASM explanations...
Post by: dcx2 on August 27, 2011, 05:11:58 PM
Quote from: Stuff on August 27, 2011, 06:43:45 AM
Well. I didn't think about branching to the end if >=. I was thinking if it's greater than the max, just rewrite the max.
I originally thought that too, but then I figured I'd optimize it a bit.  This would be the other way.

lwz r0, 1952(r31)    # read current health
lwz r12, 1956(r31)   # read max health
srawi r10,r12,8       # r10 = r12 / 256
add r0, r10, r0       # healed by ~0.4%
cmpw r0,r12          # is current <= max health?
ble- _STORE         # skip the "ceiling"
mr r0,r12              # apply "ceiling" so that current hp goes no higher than max hp
_STORE:
stw r0, 1952(r31)  #store new hp

QuoteBranch labels are interesting. I know nothing about them. Can they be called _anything? Or was _END one of the many/few labels?
Branch labels can be pretty much anything, although there might be some rules about starting with numbers.  I usually prefix branch labels with _ by convention.  This is not a requirement, but it helps me recognize a branch label that's separate from a .set variable.  The label is declared with the name ending in a :  There must be only one branch label declared with a given name, though you can use many different branch labels.  To use a branch label you just put its name without the :  Branch labels can be subtracted to create offsets.  There's also some magic single-digit labels that can be re-used.


Quote
It worked pretty nice. But that heal rate is so weird. it got annoying after a while. It was healing 10 hp each time. But at the rate it heals...Like, you can do a combo, sheathe your weapon, get hit, use a megapotion and nothing happens...and then out of nowhere, +10+10+10+10+10....+10+10..+10......>.>...<.<...:p..+10+10. XD. I'm gonna reduce it even more, but in the end, I might just do a +1/+2. It's a very nice code though. It's worthy of my gct.... When it gets tolerable.

Again, you should be trying to figure out what f1 is.  You should also look at the caller and see what's going on there.

Another thing you can consider is finding a different hook that runs reliably.  It doesn't have to be related to health; the hook could be reading anything about the monster, because all you need is a hook that runs for every monster every frame or so.
Title: Re: ASM explanations...
Post by: Stuff on August 27, 2011, 07:00:38 PM
I like this new other way actually. If I have to make it do +1/+2 instead of +a percent, I would've had to end with a nop.

Putting the BP tab to text view makes it float registers show hex >.>. So if your talking about this line:
8012ED44:  FC000840   fcmpo   cr0,f0,f1
nothing looks like it changes it from the break point up to this and the value was 0.18 when it reached that line.  >.> But it did change. It was originally 0.18 and it changed back to 0.18 after this
8012ED38:  C8010010   lfd   f0,16(r1)

>.> but thats f0. before the fcmpo, f0 was 1 at max hp, 0.310077 at 800/2580 hp and 0.893023 at 2304/2580 hp. It almost looks kind of obvious that it's checking if the hp is less than 18%. It'll probably start to limp at this point. But I don't see how the next instructions would handle that. Well..idk what the next instructions are. >.<
Almost obvious because...you never know.

I'll check the call stack next and look for something else that reads every frame maybe. Probably rage.
----
yup. 18% is when Lagiacrus limps. But he's ready to capture before then.
Title: Re: ASM explanations...
Post by: dcx2 on August 27, 2011, 07:15:41 PM
Quote from: Stuff on August 27, 2011, 07:00:38 PM
if your talking about this line:
8012ED44:  FC000840   fcmpo   cr0,f0,f1
nothing looks like it changes it from the break point up to this and the value was 0.18 when it reached that line.  >.> But it did change. It was originally 0.18 and it changed back to 0.18 after this
8012ED38:  C8010010   lfd   f0,16(r1)

>.> but thats f0. before the fcmpo, f0 was 1 at max hp, 0.310077 at 800/2580 hp and 0.893023 at 2304/2580 hp. It almost looks kind of obvious that it's checking if the hp is less than 18%. It'll probably start to limp at this point. But I don't see how the next instructions would handle that. Well..idk what the next instructions are. >.<
There ya go.  Now you see what it's trying to do.

I don't know why but sometimes the fregs are..."wrong".  And then they'll be "right" later.

The instructions that cause him to limp are probably handled by the caller.  All this function is supposed to do is determine if the monster's HP is <18% (or >18%?  I'm still not sure.  It really does look like it's masking the EQ bit off but that makes no sense, it should be masking LT or GT).

QuoteI'll check the call stack next and look for something else that reads every frame maybe. Probably rage.
That would be looking for new breakpoints based on the rage value.  You could even use something like a coordinates breakpoint, possibly.
Title: Re: ASM explanations...
Post by: Stuff on August 27, 2011, 08:29:21 PM
Maybe cuz the fregisters are 64 bits? And gecko.net reads it as 32bits or something and possibly, the next 32 bits overlap the first 32 bits of the next fregister. idk. Just an idea.

Coordinates sounds like a good idea. I found quite a few things that change while he moves in  +/-B18 from his hp. >.>

The first one looked good enough though. It looked like bully's teleport. here's a read BP and a write BP

[spoiler=read BP] CR:88200488  XER:00000000  CTR:800612A4 DSIS:00400000
DAR:9014B968 SRR0:800513CC SRR1:0000B032   LR:80073F88
  r0:800E1BF4   r1:807AD560   r2:8079DAA0   r3:9014B968
  r4:9014B968   r5:807AD590   r6:00000001   r7:00000001
  r8:00000001   r9:00000001  r10:00000001  r11:80000000
r12:800612A4  r13:80798E20  r14:00000000  r15:00000000
r16:00000000  r17:00000000  r18:9014CF70  r19:816884E8
r20:817C5000  r21:00000020  r22:00000003  r23:00000000
r24:00000000  r25:00000000  r26:00000000  r27:8017F138
r28:9014B964  r29:00000000  r30:00000006  r31:9014B968

  f0:C09A029F   f1:BE567786   f2:80000000   f3:BBA68F4B
  f4:3F190000   f5:BD3ED35A   f6:3EB13A1E   f7:00000000
  f8:3D3E80E2   f9:BD4D4879  f10:3D886B35  f11:3D4BFE51
f12:380FE13C  f13:3B0A0AAD  f14:00000000  f15:00000000
f16:00000000  f17:00000000  f18:00000000  f19:00000000
f20:00000000  f21:00000000  f22:00000000  f23:00000000
f24:00000000  f25:00000000  f26:00000000  f27:00000000
f28:00000000  f29:00000000  f30:40000000  f31:00000000

800513CC:  E0040000   psq_l   f0,0(r4),0,0 #break
800513D0:  E0250000   psq_l   f1,0(r5),0,0
800513D4:  1000082A   ps_add   f0,f0,f1
800513D8:  F0030000   psq_st   f0,0(r3),0,0
800513DC:  E0048008   psq_l   f0,8(r4),1,0
800513E0:  E0258008   psq_l   f1,8(r5),1,0
800513E4:  1000082A   ps_add   f0,f0,f1
800513E8:  F0038008   psq_st   f0,8(r3),1,0
800513EC:  4E800020   blr   
[/spoiler]

[spoiler=write BP]  CR:88200488  XER:00000000  CTR:800621E4 DSIS:02400000
DAR:9014B968 SRR0:80041E74 SRR1:0000B032   LR:80041E58
  r0:80138EB0   r1:807AD610   r2:8079DAA0   r3:9014B968
  r4:9014BAC8   r5:000000FF   r6:00000005   r7:00000001
  r8:00000001   r9:00000001  r10:00000001  r11:80000000
r12:800621E4  r13:80798E20  r14:00000000  r15:00000000
r16:00000000  r17:00000000  r18:9014CF70  r19:816884E8
r20:817C5000  r21:00000020  r22:00000003  r23:00000000
r24:00000000  r25:00000000  r26:00000000  r27:8017F138
r28:FFFFFFFF  r29:9014B940  r30:9014B940  r31:9014B968

  f0:C418D77C   f1:3F7D70A4   f2:C53B8000   f3:4544E000
  f4:B6E607EB   f5:3DBA2FA0   f6:3D886C19   f7:3EAAAAAA
  f8:3E124924   f9:3DBA2E6E  f10:3D886B35  f11:3D4BDAEE
f12:3515D8CA  f13:380FC43F  f14:00000000  f15:00000000
f16:00000000  f17:00000000  f18:00000000  f19:00000000
f20:00000000  f21:00000000  f22:00000000  f23:00000000
f24:00000000  f25:00000000  f26:00000000  f27:00000000
f28:00000000  f29:00000000  f30:00000000  f31:00000000

80041E70:  C0040000   lfs   f0,0(r4)
80041E74:  D0030000   stfs   f0,0(r3) #break
80041E78:  C0040004   lfs   f0,4(r4)
80041E7C:  D0030004   stfs   f0,4(r3)
80041E80:  C0040008   lfs   f0,8(r4)
80041E84:  D0030008   stfs   f0,8(r3)
80041E88:  4E800020   blr   [/spoiler]
With either of these, I could still use X(r31). Just X has to be a lesser number. I'm leaning towards the write BP cuz the read BP uses psq >.>. I haven't seen that yet.
Title: Re: ASM explanations...
Post by: dcx2 on August 27, 2011, 10:59:00 PM
Those might be bad hooks because they look like they run for everyone and not just enemies.
Title: Re: ASM explanations...
Post by: Stuff on August 27, 2011, 11:19:13 PM
o.O how do you see that? I'll go back to the rage idea then. I believe one of them is read often.
Title: Re: ASM explanations...
Post by: dcx2 on August 27, 2011, 11:29:02 PM
I've looked for enough hooks that I can recognize some things.  Typically, small functions like that which don't create stack frames and primarily copy data from one address to another are run for most people.  Set an XBP on the same address the RBP or WBP found.  If you have to set many XBPs before a frame goes by, then each one is someone else that the function is working on.
Title: Re: ASM explanations...
Post by: Stuff on August 28, 2011, 12:19:15 AM
Hmm. That was pretty awesome. I did a XBP on the read one.

[spoiler]  CR:22200488  XER:20000000  CTR:8007DDFC DSIS:02400000
DAR:9014B945 SRR0:800513CC SRR1:0000B032   LR:800513B0
 r0:80292260   r1:807AD470   r2:8079DAA0   r3:807AD4F8
 r4:807AD584   r5:807AD4EC   r6:00000000   r7:00000142
 r8:00000001   r9:00000000  r10:00000001  r11:807AD5E0
r12:8007DDFC  r13:80798E20  r14:00000000  r15:00000000
r16:00000000  r17:00000000  r18:9014AB7C  r19:0000FFFF
r20:00000142  r21:00000000  r22:806AC088  r23:00000000
r24:00000000  r25:00000001  r26:807AD68C  r27:807AD680
r28:00000000  r29:807AD4F8  r30:807AD584  r31:807AD4EC
[/spoiler]
Not only did the r31 jump from a nice X(r31) to a terrible one, r18 shows like it's working with player1 or player2. :/

well. rage trigger, rage counter, stamina, something weren't good hooks. But this one looks nice. It's a read BP at monster id. I couldn't get a write BP because..The id won't be changing ever. X(r3) looks good this time.

[spoiler]
 CR:24200488  XER:20000000  CTR:00000020 DSIS:00400000
DAR:9014B943 SRR0:800F3798 SRR1:0000B032   LR:800F377C
 r0:00000000   r1:807AD5B0   r2:8079DAA0   r3:9014B940
 r4:0000000C   r5:000000FF   r6:00000005   r7:00000000
 r8:00000017   r9:FFFFFFE9  r10:00000000  r11:807AD5F0
r12:8007DDFC  r13:80798E20  r14:00000000  r15:00000000
r16:00000000  r17:00000000  r18:9014CF70  r19:816884E8
r20:817C5000  r21:00000020  r22:00000001  r23:00000000
r24:806A11B8  r25:9014A334  r26:00000000  r27:00000000
r28:00000000  r29:9014AB40  r30:806A11B8  r31:806A11B8

 f0:468CA000   f1:44E10000   f2:47938E00   f3:59800004
 f4:00000000   f5:3F800000   f6:3B4CCCCD   f7:3F800000
 f8:00000000   f9:40000000  f10:3F800000  f11:BB088889
f12:3ACCCCCD  f13:00000000  f14:00000000  f15:00000000
f16:00000000  f17:00000000  f18:00000000  f19:00000000
f20:00000000  f21:00000000  f22:00000000  f23:00000000
f24:00000000  f25:00000000  f26:00000000  f27:00000000
f28:00000000  f29:00000000  f30:00000000  f31:00000000

800F3604:  9421FFC0   stwu   r1,-64(r1)
800F3608:  7C0802A6   mflr   r0
800F360C:  90010044   stw   r0,68(r1)
800F3610:  39610040   addi   r11,r1,64
800F3614:  483637DD   bl   0x80456df0
800F3618:  7C781B78   mr   r24,r3
800F361C:  38A00000   li   r5,0
800F3620:  98A301D9   stb   r5,473(r3)
800F3624:  3C800001   lis   r4,1
800F3628:  3804FFFF   subi   r0,r4,1
800F362C:  B00301DC   sth   r0,476(r3)
800F3630:  98A301E2   stb   r5,482(r3)
800F3634:  98A301E5   stb   r5,485(r3)
800F3638:  98A301E8   stb   r5,488(r3)
800F363C:  98A301EB   stb   r5,491(r3)
800F3640:  98A301DA   stb   r5,474(r3)
800F3644:  B00301DE   sth   r0,478(r3)
800F3648:  98A301E3   stb   r5,483(r3)
800F364C:  98A301E6   stb   r5,486(r3)
800F3650:  98A301E9   stb   r5,489(r3)
800F3654:  98A301EC   stb   r5,492(r3)
800F3658:  98A301DB   stb   r5,475(r3)
800F365C:  B00301E0   sth   r0,480(r3)
800F3660:  98A301E4   stb   r5,484(r3)
800F3664:  98A301E7   stb   r5,487(r3)
800F3668:  98A301EA   stb   r5,490(r3)
800F366C:  98A301ED   stb   r5,493(r3)
800F3670:  38600000   li   r3,0
800F3674:  4BFDC41D   bl   0x800cfa90
800F3678:  2C030000   cmpwi   r3,0
800F367C:  41820290   beq-   0x800f390c
800F3680:  3B232274   addi   r25,r3,8820
800F3684:  38600002   li   r3,2
800F3688:  4BFDC409   bl   0x800cfa90
800F368C:  7C7D1B78   mr   r29,r3
800F3690:  2C030000   cmpwi   r3,0
800F3694:  41820278   beq-   0x800f390c
800F3698:  4BFDBB81   bl   0x800cf218
800F369C:  5460063E   rlwinm   r0,r3,0,24,31
800F36A0:  28000002   cmplwi   r0,2
800F36A4:  4182001C   beq-   0x800f36c0
800F36A8:  4BFDBCDD   bl   0x800cf384
800F36AC:  7C600774   extsb   r0,r3
800F36B0:  1C000B20   mulli   r0,r0,2848
800F36B4:  7FBD0214   add   r29,r29,r0
800F36B8:  3B800000   li   r28,0
800F36BC:  48000008   b   0x800f36c4
800F36C0:  3B9D0B20   addi   r28,r29,2848
800F36C4:  482BA231   bl   0x803ad8f4
800F36C8:  5460063E   rlwinm   r0,r3,0,24,31
800F36CC:  2800000B   cmplwi   r0,11
800F36D0:  40820014   bne-   0x800f36e4
800F36D4:  7F03C378   mr   r3,r24
800F36D8:  7FA4EB78   mr   r4,r29
800F36DC:  4BFFFE11   bl   0x800f34ec
800F36E0:  4800022C   b   0x800f390c
800F36E4:  482BA211   bl   0x803ad8f4
800F36E8:  5460063E   rlwinm   r0,r3,0,24,31
800F36EC:  28000006   cmplwi   r0,6
800F36F0:  40820014   bne-   0x800f3704
800F36F4:  7F03C378   mr   r3,r24
800F36F8:  7FA4EB78   mr   r4,r29
800F36FC:  4BFFFE59   bl   0x800f3554
800F3700:  4800020C   b   0x800f390c
800F3704:  3B400000   li   r26,0
800F3708:  3B600000   li   r27,0
800F370C:  7F1FC378   mr   r31,r24
800F3710:  3AE00000   li   r23,0
800F3714:  3AC00001   li   r22,1
800F3718:  2C1A0003   cmpwi   r26,3
800F371C:  408001F0   bge-   0x800f390c
800F3720:  A0190006   lhz   r0,6(r25)
800F3724:  2C000000   cmpwi   r0,0
800F3728:  418201D4   beq-   0x800f38fc
800F372C:  A8190004   lha   r0,4(r25)
800F3730:  2C000000   cmpwi   r0,0
800F3734:  418201C8   beq-   0x800f38fc
800F3738:  80190000   lwz   r0,0(r25)
800F373C:  5403043E   rlwinm   r3,r0,0,16,31
800F3740:  3881000C   addi   r4,r1,12
800F3744:  38A10008   addi   r5,r1,8
800F3748:  48050E99   bl   0x801445e0
800F374C:  5460063E   rlwinm   r0,r3,0,24,31
800F3750:  28000001   cmplwi   r0,1
800F3754:  408201A8   bne-   0x800f38fc
800F3758:  8061000C   lwz   r3,12(r1)
800F375C:  88030000   lbz   r0,0(r3)
800F3760:  2C000000   cmpwi   r0,0
800F3764:  41820198   beq-   0x800f38fc
800F3768:  800301C8   lwz   r0,456(r3)
800F376C:  540007FE   rlwinm   r0,r0,0,31,31
800F3770:  2C000000   cmpwi   r0,0
800F3774:  41820188   beq-   0x800f38fc
800F3778:  480398B5   bl   0x8012d02c
800F377C:  2C030000   cmpwi   r3,0
800F3780:  4082017C   bne-   0x800f38fc
800F3784:  8061000C   lwz   r3,12(r1)
800F3788:  A003001A   lhz   r0,26(r3)
800F378C:  B01F01DC   sth   r0,476(r31)
800F3790:  7FD8D214   add   r30,r24,r26
800F3794:  8061000C   lwz   r3,12(r1)
800F3798:  88030003   lbz   r0,3(r3)  #break Gonna highlight these with blue from now on.
800F379C:  981E01E2   stb   r0,482(r30)
800F37A0:  4BFDBA79   bl   0x800cf218
800F37A4:  5460063E   rlwinm   r0,r3,0,24,31
800F37A8:  28000002   cmplwi   r0,2
800F37AC:  41820034   beq-   0x800f37e0
800F37B0:  8061000C   lwz   r3,12(r1)
800F37B4:  7FA4EB78   mr   r4,r29
800F37B8:  480398FD   bl   0x8012d0b4
800F37BC:  28030001   cmplwi   r3,1
800F37C0:  40820018   bne-   0x800f37d8
800F37C4:  8061000C   lwz   r3,12(r1)
800F37C8:  889D0008   lbz   r4,8(r29)
800F37CC:  4803E145   bl   0x80131910
800F37D0:  7C751B78   mr   r21,r3
800F37D4:  4800008C   b   0x800f3860
800F37D8:  3AA00000   li   r21,0
800F37DC:  48000084   b   0x800f3860
800F37E0:  8061000C   lwz   r3,12(r1)
800F37E4:  7FA4EB78   mr   r4,r29
800F37E8:  480398CD   bl   0x8012d0b4
800F37EC:  28030001   cmplwi   r3,1
800F37F0:  40820044   bne-   0x800f3834
800F37F4:  8061000C   lwz   r3,12(r1)
800F37F8:  889D0008   lbz   r4,8(r29)
800F37FC:  4803E115   bl   0x80131910
800F3800:  7C751B78   mr   r21,r3
800F3804:  2C030000   cmpwi   r3,0
800F3808:  40820058   bne-   0x800f3860
800F380C:  8061000C   lwz   r3,12(r1)
800F3810:  7F84E378   mr   r4,r28
800F3814:  480398A1   bl   0x8012d0b4
800F3818:  28030001   cmplwi   r3,1
800F381C:  40820044   bne-   0x800f3860
800F3820:  8061000C   lwz   r3,12(r1)
800F3824:  889C0008   lbz   r4,8(r28)
800F3828:  4803E0E9   bl   0x80131910
800F382C:  7C751B78   mr   r21,r3
800F3830:  48000030   b   0x800f3860
800F3834:  8061000C   lwz   r3,12(r1)
800F3838:  7F84E378   mr   r4,r28
800F383C:  48039879   bl   0x8012d0b4
800F3840:  28030001   cmplwi   r3,1
800F3844:  40820014   bne-   0x800f3858
800F3848:  8061000C   lwz   r3,12(r1)
800F384C:  889C0008   lbz   r4,8(r28)
800F3850:  4803E0C1   bl   0x80131910
800F3854:  48000008   b   0x800f385c
800F3858:  38600000   li   r3,0
800F385C:  7C751B78   mr   r21,r3
800F3860:  2C150000   cmpwi   r21,0
800F3864:  4082000C   bne-   0x800f3870
800F3868:  9AFE01E5   stb   r23,485(r30)
800F386C:  48000008   b   0x800f3874
800F3870:  9ADE01E5   stb   r22,485(r30)
800F3874:  8061000C   lwz   r3,12(r1)
800F3878:  88030003   lbz   r0,3(r3)
800F387C:  28000014   cmplwi   r0,20
800F3880:  4082003C   bne-   0x800f38bc
800F3884:  8803043D   lbz   r0,1085(r3)
800F3888:  28000001   cmplwi   r0,1
800F388C:  4182001C   beq-   0x800f38a8
800F3890:  28000002   cmplwi   r0,2
800F3894:  41820014   beq-   0x800f38a8
800F3898:  481BC3ED   bl   0x802afc84
800F389C:  5460063E   rlwinm   r0,r3,0,24,31
800F38A0:  28000003   cmplwi   r0,3
800F38A4:  4082000C   bne-   0x800f38b0
800F38A8:  9ADE01EB   stb   r22,491(r30)
800F38AC:  48000008   b   0x800f38b4
800F38B0:  9AFE01EB   stb   r23,491(r30)
800F38B4:  9AFE01E8   stb   r23,488(r30)
800F38B8:  48000038   b   0x800f38f0
800F38BC:  8803043D   lbz   r0,1085(r3)
800F38C0:  28000001   cmplwi   r0,1
800F38C4:  4082000C   bne-   0x800f38d0
800F38C8:  9ADE01EB   stb   r22,491(r30)
800F38CC:  48000008   b   0x800f38d4
800F38D0:  9AFE01EB   stb   r23,491(r30)
800F38D4:  8061000C   lwz   r3,12(r1)
800F38D8:  8803043D   lbz   r0,1085(r3)
800F38DC:  28000002   cmplwi   r0,2
800F38E0:  4082000C   bne-   0x800f38ec
800F38E4:  9ADE01E8   stb   r22,488(r30)
800F38E8:  48000008   b   0x800f38f0
800F38EC:  9AFE01E8   stb   r23,488(r30)
800F38F0:  9ADE01D9   stb   r22,473(r30)
800F38F4:  3BFF0002   addi   r31,r31,2
800F38F8:  3B5A0001   addi   r26,r26,1
800F38FC:  3B7B0001   addi   r27,r27,1
800F3900:  3B390010   addi   r25,r25,16
800F3904:  2C1B0006   cmpwi   r27,6
800F3908:  4180FE10   blt+   0x800f3718
800F390C:  39610040   addi   r11,r1,64
800F3910:  4836352D   bl   0x80456e3c
800F3914:  80010044   lwz   r0,68(r1)
800F3918:  7C0803A6   mtlr   r0
800F391C:  38210040   addi   r1,r1,64
800F3920:  4E800020   blr   
[/spoiler]
what is wrong with this code?

28?????? MMMMXXXX
C20F3798 00000002
800307A4 900307A0
88030003 00000000
E0000000 80008000
040F3798 88030003

This is how my map->hud (http://wiird.l0nk.org/forum/index.php/topic,5476.msg71429.html#msg71429) is. I expected it to branch when I press the activator and then undo the change immediately, which should be enough time for the new instructions to run once. The C2 basically doesn't work like this, but it does look like it works by itself because it ends up doing inf hp.
nvm. The order seems to matter. Probably because it needs the instruction until the end of the frame.

max heal all monsters
040F3798 88030003
28?????? MMMMXXXX
C20F3798 00000002
800307A4 900307A0
88030003 00000000
E0000000 80008000

lwz r0,1956(r3)
stw r0,1952(r3)
lbz r0,3(r3)

but 6 lines :/ All that for 1 less line XD.

I think I'll still use the hp BP for regen. That's a pretty cool code if you ask me.
Title: Re: ASM explanations...
Post by: dcx2 on August 28, 2011, 05:43:14 AM
Yeah, an anti-code should come before the C2.  it will write the anti-code and then immediately write the hook if the activator is true.

Have you tried doing regeneration with that address?

lwz r0, 1952(r3)    # read current health
lwz r12, 1956(r3)   # read max health
srawi r10,r12,8       # r10 = r12 / 256
add r0, r10, r0       # healed by ~0.4%
cmpw r0,r12          # is current <= max health?
ble- _STORE         # skip the "ceiling"
mr r0,r12              # apply "ceiling" so that current hp goes no higher than max hp
_STORE:
stw r0, 1952(r3)    #store new hp
lbz r0,3(r3)

C20F3798 00000005
800307A0 818307A4
7D8A4670 7C0A0214
7C006000 40810008
7D806378 900307A0
88030003 00000000
Title: Re: ASM explanations...
Post by: Stuff on August 28, 2011, 08:02:37 PM
I did this with that hook.

lwz r0, 1952(r3)    # read current health
lwz r12, 1956(r3)   # read max health
li r10, 1                #addi r0, r0, 1 seemed to do li r0, 1 >.>
add r0, r0, r10       # healed by 1
cmpw r0,r12          # is current <= max health?
ble- _STORE         # skip the "ceiling"
mr r0,r12              # apply "ceiling" so that current hp goes no higher than max hp
_STORE:
stw r0, 1952(r3)    #store new hp
lbz r0,3(r3)

It heals 1 hp per frame I guess, but that was way too fast. It's faster recovery than when they sleep. lol. I poked lagiacrus's hp to 1 and started attacking him. His hp made it back to 2580. lol. I could probably do a loop that would only add 1 at the last cycle. But idk if that would let multiple frames pass. A small % per second would be good.
Title: Re: ASM explanations...
Post by: dcx2 on August 28, 2011, 09:51:31 PM
Ah, I bet you found out you can't do addi r0,r0,1 huh?  addi is an rA|0 instruction.  So if you use r0 for rA, it will treat it as the value 0 instead of the value in r0. 

We can try this.  Write the anti-code, then use a counter-if before the C2 code.  Once per second this will heal them by 1 HP.  You can make it heal faster by lowering the counter value from 3C to e.g. 1E.  You can make it heal more by changing the addi from 1 to 2.

040F3798 88030003 # anti-code
A8000008 0000003C # 60 hz counter auto-reset counter
C20F3798 00000004
818307A0 800307A4
7C0C0000 4080000C
398C0001 918307A0
88030003 00000000
E0000000 80008000

lwz r12, 1952(r3)  # read current health
lwz r0, 1956(r3)   # read max health
cmpw r12,r0        # is current >= max health?
bge- _END          # skip healing
addi r12, r12, 1    # healed by 1
stw r12, 1952(r3) #store new hp
_END:
lbz r0,3(r3)
Title: Re: ASM explanations...
Post by: Stuff on August 28, 2011, 11:01:33 PM
That was awesome. Thanks. I didn't know you could do counter ifs without a if. I did this. addi r12, r12, 5 and it was tolerable. About every second, 5 hp gain. It's a nice recover rate with no "omg I can't do this.":

040F3798 88030003
A8000008 0000003C
C20F3798 00000004
818307A0 800307A4
7C0C0000 4080000C
398C0005 918307A0
88030003 00000000
E0000000 80008000

I'll mess with this a little bit before posting it. I might go back to %. Or even mess with monster level to determine the heal amount. XD. I wonder what it'll be like with the C2 max heal.

It only works on boss monsters. That was a little interesting.

--------------------
Hmm. What are those ps[q] instructions, if you don't mind explaining? They're not in the this: http://www.pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/ (http://www.pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/). They look like they're related somehow to lwz, stw, add.
Title: Re: ASM explanations...
Post by: dcx2 on August 30, 2011, 02:43:48 AM
ps = paired single.  ps is a lame version of SIMD (Single Instruction Multiple Data).  Other less lame versions include SSE and AltiVec.

fregs are 64-bits.  Single-precision floats are 32-bits.  ps instructions pack two singles into an freg.  A Single Instruction can then operate upon Multiple Data values at once.

ps are specific to the Gekko processor architecture.  Since they're Nintendo-specific, there isn't much info on them on the web.  About the best resource available is YAGCD, but for _l and _st it doesn't have much other than opcodes and bit fields.  http://hitmen.c02.at/files/yagcd/yagcd/chap3.html#sec3.4

psq_l and _st will do 32-bit or 64-bit loads or stores depending on one of the arguments...I can't remember which.  I think it's the first one.  The W bit field in 3.4.3 of the YAGCD link.

The Quantization registers are some kinda voodoo magic (more formally known as "SPRs" or Special Purpose Registers).  I think they're used for scaling and converting between ints and floats.  That part is actually pretty useful, if it weren't so difficult to leverage.

===

In case the dry description doesn't get the right picture in your head, the following are mostly equivalent.

lwz f0,0(r4)     # load two floats from r4
lwz f1,4(r4)

lwz f10,0(r5)    # load two more floats from r5
lwz f11,4(r5)

fadds f0,f0,f10  # add first set of floats
fadds f1,f1,f11  # add second set of floats

stw f0,0(r3)      # store two floats to r3
stw f1,4(r3)

--- or

psq_l   f0,0(r4),0,0 # load two floats from r4
psq_l   f1,0(r5),0,0 # load two floats from r5
ps_add   f0,f0,f1    # add first set to second set
psq_st   f0,0(r3),0,0 # store two floats to r3
Title: Re: ASM explanations...
Post by: Stuff on August 30, 2011, 04:40:58 AM
Interesting. My head exploded, but I'm alright . :D

Do you know if there's a guide on the safety of the fregs like the one you have for registers? fregs sound like fun. I probably won't mess with it much, though.
Title: Re: ASM explanations...
Post by: dcx2 on August 30, 2011, 04:43:40 AM
It's been a while since I looked, but it works pretty much the same way.  Except there aren't any special registers like r1/r2/r13.

EDIT:

In terms of good ASM explanations, I found this stuff from brkirch on rlwinm and rlwimi.  Very useful instructions.

http://wiird.l0nk.org/forum/index.php/topic,2844.msg29959.html#msg29959
Title: Re: ASM explanations...
Post by: Stuff on August 31, 2011, 07:12:20 AM
Ah good to know, I guess. I'll hope I'll never need more than f12 :D

oh man. That's very nice info. Another page I'll be looking at until it sticks. I was wondering what those were. That Collective is pretty beefy. lol.

wonder why I wasn't notified about this reply. >.>
Title: Re: ASM explanations...
Post by: dcx2 on September 02, 2011, 08:52:35 PM
In keeping with the theme of the thread, I'm going to add links to post that describe various things.   Here's an example code which takes three integers in r4, r5, r6, converts them to float, multiplies them by customizable floats embedded with the bl trick, and then converts the floats back to integers in r26,r27,r28.  It's nice to see the conversions to and from float all in one place.

http://wiird.l0nk.org/forum/index.php/topic,8757.msg73781.html#msg73781

It's worth noting that the thought "will I need more than f12" is the wrong approach.  You should start at f12 and work your way toward f0 ("I'll hope I'll never need less than f0").  Hence why my code starts at f12, and then uses f11, f10, and f9.

[spoiler=dcx2 said...]
Quote from: Xenom on August 26, 2011, 07:29:47 AM
I'm trying to REDUCE the exp multiplier and had a bit of success by using:
040C1550 1F45xxxx - although it was semi-successful, I have the feeling that I'm going about this all the wrong way (shifting bits?)

1F = multiply instruction?
44 = offset in memory to multiply with?
xxxx = unsigned 16-bit integer?

0x1F44XXXX = mulli r26,r4,0xXXXX.  The 1F doesn't neatly map to "mulli"; the first 6 bits, 0x1C, are the op code for mulli.  The next five bits are the first register operand, the next five bits are the second register operand, and the last 16 bits are the immediate.

You could get by using right-shifts to divide by powers of 2, but that will only get you .5, .25, .125, etc.  Not very practical.  You could use fixed point multiplies but that's pretty difficult for other people to customize.

Quote from: mugwhump on September 02, 2011, 09:45:27 AM
I too am extremely interested in this, and I know quite a few other people who would be too. Unfortunately my USB Gecko broke.  :-\

Exactly how successful was your attempt? What value did you use?

I'm pretty sure it's just standard integer multiplication. We need some float multiplication.


QuoteOriginal codes:
$EXP multiplier [Thomas83Lin]
040C1550 1F44xxxx
**Ported from Unknown*

$AP multiplier [Thomas83Lin]
040C1554 1F65xxxx
**Ported from Unknown*

$SP multiplier [Thomas83Lin]
040C1558 1F86xxxx
**Ported from Unknown*

This code will do all three.  I don't have this game and can't test it, but I'm reasonably sure it will work.

This code uses the red zone.  The red zone is addressed by using "negative stack frames", i.e. -8(r1) and -4(r1).  It allows you to avoid creating a stack frame if you don't need to, but you must be careful because the USB Gecko debugger will over-write this area if you step through it.  Hence why it's a "red" zone.

The three 3F800000's at the beginning are the EXP, AP, and SP multipliers in single-precision floating-point format.  3F000000 = 0.5, 3F400000 = 0.75, 3FC00000 = 1.5 etc

Some important things to note about the PowerPC architecture.  1) Double-precision instructions can take single-precision operands, but the result is double-precision.  That is why I can fmuls and then fctiwz and then stfd.  2) Single-precision instructions can take double-precision operands, but produce single-precision results.  That is why I can lfd and then fsubs.

[spoiler=source]hook  800C1558:  7CDC3378   mr   r28,r6

# multipliers

bl _SKIP_DATA
.float 1.0      # EXP
.float 1.0      # AP
.float 1.0      # SP
_SKIP_DATA:

# load fregs

lfd f12,-32360(r2)   # load magic float into f12, -32360(r2) varies for each game and region
stfd f12,-8(r1)      # store magic float onto stack to create the 0x43300000

xoris r26,r4,0x8000   # load flipped-int
stw r26,-4(r1)      # store flipped-int to stack
lfd f11,-8(r1)      # load flipped-int into f11
fsubs f11,f11,f12   # normalize f11

xoris r27,r5,0x8000
stw r27,-4(r1)   
lfd f10,-8(r1)   
fsubs f10,f10,f12   

xoris r28,r6,0x8000
stw r28,-4(r1)   
lfd f9,-8(r1)      
fsubs f9,f9,f12   

# f11/f10/f9 have EXP/AP/SP

mflr r12

lfs f12,0(r12)      # load EXP mul
fmuls f11,f11,f12   # scale EXP

lfs f12,4(r12)      # load AP mul
fmuls f10,f10,f12   # scale AP

lfs f12,8(r12)      # load SP mul
fmuls f9,f9,f12      # scale SP

# store scaled versions

fctiwz f11,f11      # convert from double to int
stfd f11,-8(r1)      # store conversion
lwz r26,-4(r1)      # load conversion

fctiwz f10,f10   
stfd f10,-8(r1)   
lwz r27,-4(r1)   

fctiwz f9,f9      
stfd f9,-8(r1)   
lwz r28,-4(r1)
[/spoiler]

EXP/AP/SP float multiplier [dcx2]
C20C1558 00000012
48000011 3F800000
3F800000 3F800000
C9828198 D981FFF8
6C9A8000 9341FFFC
C961FFF8 ED6B6028
6CBB8000 9361FFFC
C941FFF8 ED4A6028
6CDC8000 9381FFFC
C921FFF8 ED296028
7D8802A6 C18C0000
ED6B0332 C18C0004
ED4A0332 C18C0008
ED290332 FD60581E
D961FFF8 8341FFFC
FD40501E D941FFF8
8361FFFC FD20481E
D921FFF8 8381FFFC
60000000 00000000
modified base on Thomas83lin/Unknown's work

For just the EXP multiplier (again, change the 3F800000)
C20C1550 00000008
48000009 3F800000
C9828198 D981FFF8
6C9A8000 9341FFFC
C961FFF8 ED6B6028
7D8802A6 C18C0000
ED6B0332 FD60581E
D961FFF8 8341FFFC
60000000 00000000

[/spoiler]
Title: Re: ASM explanations...
Post by: Stuff on September 18, 2011, 05:13:47 AM
8004FE84:  38000005   li   r0,5
8004FE88:  7C0903A6   mtctr   r0
....
8004FEC4:  4200FFC8   bdnz+   0x8004fe8c

I did some googling first, I just want to make sure I got this right cuz bdnz sounds ridiculous. Before and after reading it.
So I can think of this as a loop, right? for (ctr=5; ctr>0; ctr--)
mtctr sounds simple, but is bdnz really doing ctr-- and then for lack of better words(I know it's a terrible example):
cmp "ctr", 0
bne 0x8004fe8c

Pretty awesome if so. I think I just learned an awesome combo.
Title: Re: ASM explanations...
Post by: dcx2 on September 18, 2011, 03:38:32 PM
Yes, that is a correct interpretation of bdnz+.  Branch Decrement Not Zero.  The decrement to ctr happens first (important).  Then the cmpwi ctr, 0.  Then the b is taken or not taken.  The conditional branch instruction datasheet page indicates that you can also combine a conditional branch like bne with a bdnz, however I've not done this so I am unsure of what the mnemonic would look like.
Title: Re: ASM explanations...
Post by: Stuff on September 26, 2011, 05:42:42 AM
What's the advantage of using ori instead of addi? I've seen this a few times:

lis rX, YYYY
ori rX, rX, ZZZZ
...

And always wondered what ori was for, and I saw it now when I thought about 'li word' being impossible unless I get funky with it. I was thinking something like this:

lis rX, YYYY
addi rX, ZZZZ
...

And this works. But it looks like everyone prefers ori.

Also if I do this
lis r0, 8
will r0=80000000 or 00080000?
Title: Re: ASM explanations...
Post by: goemon_guy on September 26, 2011, 11:21:08 AM
I'm pretty sure that ori and addi can be used to achieve the same thing, (loading an address,) but it's just a matter of preference.

Just like you could do:

lis rX, 0xZZZZ
lhz rY,0xTTTT(rX)
...

To load a value from an address as well.
I'd say it's just a preference.

If you do

lis r0, 8

It's the same as 0x0008, so:
r0=00080000
Title: Re: ASM explanations...
Post by: Stuff on September 26, 2011, 01:59:15 PM
Well I just realized that addi anything > 7FFF becomes subi. That's a problem. I was messing around with controller digits and came across this. 80660000-8000 != 80660000+8000 >.<. Of course, I could add 1 to the lis, but ori is superior here since it's not adding or subtracting. It just fills in the last 16 bits. Guess I'll be using ori now.

Good to know that lis does that. I was hoping for that. Cuz if lis 0x8000 and lis 8 did the same thing...>.>
Title: Re: ASM explanations...
Post by: dcx2 on September 26, 2011, 03:15:06 PM
As you have discovered, addi and subi sign extend the immediate.  This makes them very unwieldy to use for loading addresses, because the sign-extended bits end up modifying the half-word loaded with lis.  This is also the reason that the assembler supports @ha - the a takes care of the sign extension by adding 1 if it is needed to compensate for the subi.

Displacement operands (i.e. the d in lwz rS,d(rD)) are also signed.  So if d > 0x7FFF, then you will also need to increment the lis value.

It's also worth pointing out that ori doesn't "fill" the lower half-word.  Rather, it uses the immediate as a one's hot mask to set bits.  This is not normally a problem, because lis will clear the lower half-word.  But in the event that you try to get clever, it will backfire.  If you were to do something like

lis r12,0x8012
ori r12,r12,0x2344    # r12 = 80122344
ori r12,r12,0x8044    # r12 = 8012A344
Title: Re: ASM explanations...
Post by: Stuff on September 26, 2011, 04:06:31 PM
@ha? I googled it to understand. But Pyiiasmh doesn't handle it right. Or maybe this is what I did:

lis r5,33@ha
subi r5,r5,30827
| to gecko code
\/
3CA00000 38A58795
| to asm
\/
lis r5,0
subi r5,r5,30827

Is that @ha usable with displacement operands?

ori: well yeah. I just meant it if the lower half-word was 0 since lis shifts to the upper(?) half-word. I don't know why I would want to OR twice. I'm not there yet. But now I'll be messing with it to see what can be done with OR, XOR, and AND. :p
Title: Re: ASM explanations...
Post by: dcx2 on September 26, 2011, 04:20:15 PM
er, it appears you misunderstand how @ha is supposed to work.  The code generated is technically correct.  @ha turns a 32-bit value into a 16-bit value preserving the high word.  @l is the complementary way to load the low word.

Take for example 0x80128344.  Say you wanted to load this into r12 using fancy ASM.

.set some_pointer,0x80128344

lis r12,some_pointer@ha
ori r12,r12,some_pointer@l

When you tried "33@ha", what you got was the upper 16-bits of 0x00000021
Title: Re: ASM explanations...
Post by: Stuff on September 26, 2011, 07:53:34 PM
Oh wow. That's pretty awesome. I can't even explain what I thought it was before anymore.

I ran that through pyiiasmh and got an unwanted result though:
3D808013 618C8344
^would've been correct if it wasn't followed by ori. Still pretty awesome for addi/subi. Ori is still superior when it comes to making a register some word, but that whatever-they're-called was interesting.
Title: Re: ASM explanations...
Post by: dcx2 on September 26, 2011, 07:57:54 PM
haha, that was my bad.  I'm so accustomed to using ori that I forgot you should use @h instead of @ha when using ori.  Or I forgot that you were trying to use subi.  Either way, @h doesn't compensate for sign extension.

.set some_pointer,0x80128344

lis r12,some_pointer@h        # r12 = 0x80120000
ori r12,r12,some_pointer@l

lis r11,some_pointer@ha       # r11 = 0x80130000
addi r11,r11,some_pointer@l

EDIT:

I should also note that in the case the @l part will NOT be sign extended, @ha is equivalent to @h

.set some_pointer,0x80122344

lis r12,some_pointer@h        # r12 = 0x80120000
ori r12,r12,some_pointer@l

lis r11,some_pointer@ha       # r11 = 0x80120000
addi r11,r11,some_pointer@l
Title: Re: ASM explanations...
Post by: Stuff on September 30, 2011, 07:36:10 AM
This one goes back to masks in the if codetypes. I want to add a mask to button activators, but in asm. I think this is the way to do it:

lis r12,0x8066
lhz r12, 0xffff93DC(r12)
andi. r12, r12, 0x800
cmplwi r12, 0x800

not(MMMM) = XXXX normally and I think this is what ifs do. That they AND the stuff from the address and then compare it to your button digits. Which would be XXXX if at least that's being pressed. But maybe I think this works because I used such a simple number as an example(0b100000000000).

This isn't very efficient considering if codetypes can handle this with 1 line, but I'm seeing these not needing a terminator and by adding this to a C2 code, I can make it run the original instructions or my instruction depending on if the button is pressed.

I was gonna say something about CR0, but I do a cmplwi right after andi.. Safe to assume it's safe? I have seen cmp's followed by a few instructions before branching.
Title: Re: ASM explanations...
Post by: Bully@Wiiplaza on September 30, 2011, 10:53:31 AM
Quote from: Stuff on September 30, 2011, 07:36:10 AM
lis r12,0x8066
lhz r12, 0xffff93DC(r12) # lhz only loads a 16bit value (93DC). Is the ffff part needed/accepted by the assembler program?
andi. r12, r12, 0x800 # doesn´t andi. replace a cmpwi?
cmplwi r12, 0x800 # why do we need two compare instructions? :confused:
beq- or bne- now?
and what´s the difference in usage of a cmpwi and cmplwi?
As far as I know, andi. is for masked buttons and cmpwi for non-masked ones.
Btw. button activators in asm can e.g. be used as rollers or just to pack everything into a C2 without multiple "code parts".
And it´s always shorter than using a 28 codestype + C2 + End if + Default line + Terminator.
Execution will then be decided inside the C2 :P
Title: Re: ASM explanations...
Post by: dcx2 on September 30, 2011, 02:52:34 PM
Quote from: Stuff on September 30, 2011, 07:36:10 AM
lis r12,0x8066
lhz r12, 0xffff93DC(r12)
andi. r12, r12, 0x800
cmplwi r12, 0x800

First thing I noticed is that your displacement operand is negative.  So this will be reading from 806593DC.

Second thing I noticed is that you don't need a cmp.  The . at the end of andi. is a cmpwi r12, 0.  If your button is pressed, then the result of andi. will be Not Equal.  If the button is not pressed, the result will be Equal.  It's kinda the opposite of cmpwi/cmplwi.  andi. can't be used to test for multiple simultaneous buttons, that requires a cmp.  But it can test for a single button easily.

The safety of CR0 inside a C2 code is determined by what lies around the hook.  If your hook is between a cmp or . instruction and its associated branch, you will get weird side effects.  In that case, I usually hook the cmp or . instruction, and place it at the end so CR0 is correct when we branch back to the game.
Title: Re: ASM explanations...
Post by: Stuff on September 30, 2011, 05:13:20 PM
Awesome. Many thanks guys. I can now shorten my max heal all monsters 1 more line even with a mask maybe. I didn't realize andi. does a cmpwi.

The reason I use cmplwi instead of cmpwi is because I ran into a signed issue here (http://wiird.l0nk.org/forum/index.php/topic,5476.msg73951.html#msg73951). CC right is 8000 and for some reason, cmpwi wasn't accepting 8000+ as 8000+. probably because it was looking for FFFF8000 and not 8000. And it makes sense now sort of. that's why I had to do lhz r12, 0xffff93DC(r12). I was experimenting with using hex instead of decimal in pyiiasmh and it was working fine until I did lhz r12, 0x93DC(r12). "Error: operand out of range (0x000093dc is not between 0xffff8000 and 0x00007fff)". Thank you captain obvious. When was the last time you interpreted A18C93DC as lhz r12,+27684(r12)?

806593DC is the classic controller address.

Quote from: dcx2 on September 30, 2011, 02:52:34 PMandi. can't be used to test for multiple simultaneous buttons, that requires a cmp.  But it can test for a single button easily.
D: I can for multiple simultaneous buttons, but only by using more code space.
"." is always cmpwi rA, 0? I wish it was cmpwi rA, UIMM just for andi.. >.<
Title: Re: ASM explanations...
Post by: dcx2 on September 30, 2011, 05:35:11 PM
.set CC_ADDR, 0x806593DC

lis r12,CC_ADDR@ha
lhz r12,CC_ADDR@l(r12)
andi. r12,r12,0x800
# cmpwi here if you mask multiple buttons to make sure they are all held
beq- _NO_HACK

# do hack stuff here

_NO_HACK:

---

That will circumvent the sign extension problem in PyiiASMH.

You are also correct, cmplwi = compare logical word immediate.  http://pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/cmpli.html  See how it says UIMM?  Unsigned IMMediate.  So it will not sign extend the immediate.

http://pds.twi.tudelft.nl/vakken/in101/labcourse/instruction-set/cmpi.html  SIMM = Signed IMMediate.  So it will extend the sign bit, which explains all the additional f's.

---

In your link, you used lhz (which does not sign extend the halfword) with cmplwi (which does).  If you had used lha instead, then the halfword that was loaded would be sign-extended and cmplwi would work.

. will always do cmpwi 0 (NOT cmplwi).  That is true for ANY instruction with a dot.  subic. rlwinm. etc.  Some instructions have an optional dot (rlwinm), others don't (andi.)

---

For multi-button activators, I often use an "enable" button (e.g. hold Z to enable hax), and then combine this with other buttons (press left or right arrow to roll value up or down).

First, you need both the delta activators and the typical activators loaded.  Then andi. the delta activators to see if e.g. left or right was just pressed.  If they weren't just pressed, beq- _END.  If they were pressed, use cmpwi's with the delta'd button and the enable button.

Here's my shop roller for ToS.  It's a GC game so the button masks are different, and the delta activators are +0x30 from buttons for GC instead of +4 for Wii.  But this is a good example to examine because it's a straight forward roller.

[spoiler]hook  800C70D8:  A8030016   lha   r0,22(r3)

z up or z down to roll shop

limits are 0 to 51

shop roller



# =========================================

.set BTN_ADDR,0x802CAED8

.set BTN_Z,0x0010
.set BTN_DUP,0x0008
.set BTN_DDOWN,0x0004


lha r10,22(r3)         # original instruction

lis r12,BTN_ADDR@ha      # r12 = button pointer
lhz r11,BTN_ADDR@l+0x30(r12)   # r11 = deltas
andi. r11,r11,BTN_DUP|BTN_DDOWN   # check for up or down changing
beq- _END

lhz r11,BTN_ADDR@l(r12)      # r11 = buttons

cmpwi r11,BTN_Z|BTN_DUP      # z dup incs
bne- 0f

addi r10,r10,1         # inc
cmpwi r10,51         # wrap
ble- 0f

li r10,0         # from 52 to 0

0:

cmpwi r11,BTN_Z|BTN_DDOWN   # z ddown decs
bne- 0f

subic. r10,r10,1      # dec
bge- 0f

li r10,51         # from 0 to 52

0:

_END:

sth r10, 22(r3)         # store rolled value
mr r0,r10         # finish original instruction[/spoiler]
Title: Re: ASM explanations...
Post by: Stuff on September 30, 2011, 06:56:56 PM
Quote from: dcx2 on September 30, 2011, 05:35:11 PMIn your link, you used lhz (which does not sign extend the halfword) with cmplwi (which does).  If you had used lha instead, then the halfword that was loaded would be sign-extended and cmplwi would work.
lhz worked though. Should I still change it to lha? I thought cmpwi was the problem since cmplwi fixed it.

I should start using these variable XD. In your spoiler, you used a different kind of branch label. 0f which points to 0:. Is it something special or is that just a regular label?

Your example showed me that there's still hope >.<. I wanted to see if my problem with Bully's speedhack could be fixed if I put the activators in the asm instead. The code works by itself, but as soon as I put activator buttons, it stopped working in some places. idk why. But I just didn't want to always be super running. I could check for 1 button that I would press along with R, and then it would work from there since you have to be pressing R to run anyway.
Title: Re: ASM explanations...
Post by: dcx2 on September 30, 2011, 07:20:55 PM
You can use lhz with cmpwi or lha with cmplwi.  Doesn't matter, they're both functionally the same.  lhz/cmpwi is probably more intuitive because it's not doing implicit sign extensions.

Labels which are a single digit can be re-used.  0f will go to the next 0: label, 0b will go to the previous 0: label.  They're nice when you don't want to come up with five billion label names.
Title: Re: ASM explanations...
Post by: Stuff on October 01, 2011, 05:01:39 PM
I want to multiply. I'm assuming low word is fine, cuz we don't have 64 bits to work with >.>. And I just want to use mulli(high word has no immediate). I am thinking of this correctly, right? There isn't some kind of funky split going on here where it'll only multiply the lower 16 bits of the word.
Title: Re: ASM explanations...
Post by: dcx2 on October 03, 2011, 03:01:50 AM
mulli will multiply the two 32-bit values (EDIT: the 32-bit value in rS, and the sign-extended 16-bit immediate in the mulli), and truncate the upper 32-bits in the event that they aren't already 0.

mullw and mulhw can be used to get the lower and upper (respectively) 32-bits of a multiply.

mulhw can be useful if you know you're doing fixed point multiplies.  Put the 32-bit whole in one reg, 32-bit fraction in another, mulhw, and the destination reg will have the 32-bit whole result.
Title: Re: ASM explanations...
Post by: Stuff on October 04, 2011, 05:20:06 AM
I made this up and pyiiasmh accepted it >.>
blrl.
Please tell me this branches to the link register and then stores the next address in the link register so I can come back to it later.Put it in a code. Yes it does. Unbelievable.
Title: Re: ASM explanations...
Post by: dcx2 on October 04, 2011, 03:16:32 PM
Yup, that's what blrl does.  It's used in the code handler for C0 codes.

The "right" way to do such a thing is bctrl.  But if the ctr isn't safe, blrl is a nice substitute.
Title: Re: ASM explanations...
Post by: Stuff on October 04, 2011, 03:55:35 PM
So mtctr and then bctrl. Sounds gooder. So would it be safe if the next branch isn't a bctr? I mean, if your gonna bl, blrl would be safest imo, since your already gonna change the LR. But I'm willing to change to bctrl. Gotta do things the right way. XD
Title: Re: ASM explanations...
Post by: dcx2 on October 04, 2011, 04:44:57 PM
Well, in general bctrl is the "right" way to do it because that's how compilers do it, that's how you'll see the game do it, etc.  You will never see blrl in the game's own ASM, except for maybe some kinda hack protection.

But you're right, if you are going to bl you know lr is safe.  So from a theoretical standpoint, it is an optimization to use lr for this purpose.  But if I had to look at it, it would make me twitch a bit.  o.<

ctr is volatile (except in the code handler; o.<) so it's pretty easy to determine whether it's safe.  Basically it can only be used in loops that don't call other functions.  If a loop will call a function, you'll see it use non-volatile, from r14-r31, to hold the loop counter.
Title: Re: ASM explanations...
Post by: daijoda on October 05, 2011, 01:42:50 AM
Quote from: dcx2 on September 30, 2011, 05:35:11 PM
[spoiler]hook  800C70D8:  A8030016   lha   r0,22(r3)

z up or z down to roll shop

limits are 0 to 51

shop roller



# =========================================

.set BTN_ADDR,0x802CAED8

.set BTN_Z,0x0010
.set BTN_DUP,0x0008
.set BTN_DDOWN,0x0004


lha r10,22(r3)         # original instruction

lis r12,BTN_ADDR@ha      # r12 = button pointer
lhz r11,BTN_ADDR@l+0x30(r12)   # r11 = deltas
andi. r11,r11,BTN_DUP|BTN_DDOWN   # check for up or down changing
beq- _END

lhz r11,BTN_ADDR@l(r12)      # r11 = buttons

cmpwi r11,BTN_Z|BTN_DUP      # z dup incs
bne- 0f

addi r10,r10,1         # inc
cmpwi r10,51         # wrap
ble- 0f

li r10,0         # from 52 to 0

0:

cmpwi r11,BTN_Z|BTN_DDOWN   # z ddown decs
bne- 0f

subic. r10,r10,1      # dec
bge- 0f

li r10,51         # from 0 to 52

0:

_END:

sth r10, 22(r3)         # store rolled value
mr r0,r10         # finish original instruction[/spoiler]
I'm shocked to find out sentences like ".set WHAT_EVER, 0x12345678" can be interpreted by the converter app and actually used in address calculations. I had no idea the app understood English! LOL. So slick. Is there a manual for the kind of lingo I could use in the app?

What do the "@ha" and "@l" parts mean? Whatever they mean, I've committed the effects of such usage to memory. Is this possible too?

lis r12,WHAT_EVER@ha
lwz r12,WHAT_EVER@l(r12)

And regarding your example, could you explain the reasoning behind doing two layers of tests (checking with andi. first, if passed, cmpwi), instead of just cmpwi always?

And dcx2, I can't thank you enough for your patience.
Title: Re: ASM explanations...
Post by: Stuff on October 05, 2011, 03:11:12 AM
@ha and such (http://wiird.l0nk.org/forum/index.php/topic,8768.msg74573.html#msg74573). That and the next 2 posts have dcx2 showing how @ha and such work. It's very handy. I have buttons saved in a txt (not all of them) and pyiiasm works it's magic from there.

.set is like a variable declaration afaik. you know variables can be named whatever. And even better is that you can use hex instead of decimal with displacement and immediates and whatnot. If you ask me, it's easier to look at hex than decimal when your working with hex. >.>

This thread is jam packed with stuff. And nice advice from dcx2. I learned the most here. (still think I'm newb with asm, but alot was learned. I'll be pro in no time ;p). Anything I learned elsewhere, sometimes I come back here to confirm that I'm right. You'll probably have to skip a few things, though cuz I asked some newb stuff.
Title: Re: ASM explanations...
Post by: dcx2 on October 05, 2011, 04:41:43 AM
Yes, the example code you show works just fine.  Note that @ha should be used with addi/subi (this includes displacement operands, which are added), while @h should be used with ori.  They are not interchangeable.

Also, the app itself doesn't understand English.  It (and PyiiASMH) is a front-end for vdappc and powerpc-gekko-as.  as itself is what "understands" English.  Y.S. gave me this link when I asked about as.  http://sourceware.org/binutils/docs-2.18/as/

Regarding the two levels of testing (actually, three); there are two types of button activators.  One activator has a bit set for every button that is currently held down.  Another activator has a bit set only during the frame that a button became pressed; on the next frame the bit will be clear, even though the button is still held down.  I call these last ones "delta activators".

When using a roller code, you only want the value to roll once per press.  Otherwise, it will roll every 16 ms or so (60 Hz), which is bad if you want to dial in to a specific value.

The first test with andi. is on the delta activators.  If D pad up or D pad down were just pressed, then we will process the hack.  If they weren't just pressed, do nothing.

Once we know the up or down was just pressed, we'll test to make sure Z and up, or Z and down are being held.  Z is therefore the "enable" button; if Z isn't pressed then this test will prevent up or down from processing the hack accidentally.  If you're holding Z and press up, it will fire just once when you press up, even if you hold the buttons for a long time.

The third level of testing makes sure that when we increment to 52, it wraps around to 0.  And -1 wraps to 51.

Of note is that the code example is for a GameCube game, so some of the offsets and button values are different than for Wii games.
Title: Re: ASM explanations...
Post by: daijoda on October 05, 2011, 05:18:26 AM
Wow, that's a rather organized docs set for a homebrew app. They must've put a lot of efforts into that. I'm just glad that this is an open forum, it lowers the barrier to learning by this much by being accessible. :)

Still a little unclear about the terminology used... When people say something is sign extended, do they mean a case like when 0x8000 becomes 0xFFFF8000?

For the "delta activators", one of them would have a corresponding bit changed from "0" to "1" in the frame that button is pressed, and the other one of them would have the same bit changed in the frame the button's released?
Title: Re: ASM explanations...
Post by: dcx2 on October 05, 2011, 05:34:45 AM
as is not a homebrew app.  It's the GNU assembler.  It's part of gcc.  We're using the same tools that anyone else targeting a PowerPC architecture could use; for instance, if you wanted to compile an app for an old MacBook, you could use gcc and as.

Sign extension does basically what you said.  It copies the sign bit to the left until it fills the remaining bits of the architecture's width.  So sign extending a 16-bit value to a 32-bit value would copy the sign bit 16 times.  That means 0x8000 -> 0xFFFF8000, and 0x7FFF -> 0x00007FFF.

Sign extension is used kinda like this.  Imagine you have an 16-bit value that represents -1 in two's complement.  This would be 0xFFFF.  What if you wanted this to be a 32-bit representation of -1?  That is 0xFFFFFFFF.  Sign extension "extends" the 16-bit value so that it represents the same value for a 32-bit value.  You can also using sign extension on 8-bit values, too.

Yes, there are two delta activators for the Wii, one for presses and one for releases.  They are usually located immediately after the "classic" button activator.  I'm not sure if there's release activators for the GC.
Title: Re: ASM explanations...
Post by: Stuff on October 05, 2011, 12:12:28 PM
ah. Those are the delta activators your talkin about. I didn't see the 0x30 even though you mentioned it. >.<
That's clever. I guess I don't need to turbo activate XD.

Is it possible to lwz rA, d(SRR0)? I tried and pyiiasmh didn't complain, but instead it interpreted it as r26. :/ I was gonna branch over some ascii and then lwz them, but there isn't a reliable register that I can always use to point to it. But since SRR0 is always the address of the current instruction, it would've been awesome if I could just use that.
Title: Re: ASM explanations...
Post by: Stuff on October 27, 2011, 07:47:03 PM
cmpwi. I says the result is placed in crfD. But if we don't specify one(usually the case), I assume crf0 is where the result goes. Correct me if I'm wrong.

Now, I want to mtcr(f) so that bne- will branch. Making it always branch works fine, but I froze the game when I did li r27, 0 before a cmpwi r27, 0 oops >.>. Anyway, I still wonder what goes into crfD when a cmp happens.
Title: Re: ASM explanations...
Post by: dcx2 on October 27, 2011, 08:09:05 PM
The CR is split into eight fields, each four bits.  In the PowerPC EABI (https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf), on page 3, you can see that CR2, CR3, and CR4 are all non-volatile.  The others are volatile.  So if you make any modifications to the CR that affect these fields (2/3/4), you will want to push and pop the CR on the stack.  If you use 0/1/5/6/7 then you won't need to.  Preferably use 5/6/7 since 0/1 are used implicitly.

According to the Programmer's Reference Guide (http://www.cebix.net/downloads/bebox/PRG.pdf), page 13, each field has bits in this order from 0 to 3: less than/negative, greater than/positive, equal/zero, and overflow.

An integer instruction with a ., or a cmp with no cr specified, will use CR0.  A float instruction with a . or an fcmp with no cr will use CR1.

---

Regarding your older post that I missed because it was an edit, SRR0 is not one of the registers r0-r31.  Only a General Purpose Register (GPR) such as r0-r31 can be a pointer for lwz (and note that if you use r0, it actually uses address 0 instead of r0's contents).  Therefore you can't use SRR0 to do that.

In fact, SRR0 only reflects the current instruction during an interrupt.  During normal execution, SRR0 does not hold the instruction pointer.

The only way to figure out where you are in memory is to use bl and then mflr (aka bl trick).

EDIT:

I suppose I should add in case it's not clear.  SRR0 is a "Special Purpose Register" (SPR, as opposed to GPR).  There is a special instruction for reading/writing to SRR0; it's conveniently called mtsrr0.

When I said it only reflects the current instruction during an interrupt, I mean that...during an interrupt, well, "normal execution" is paused and the processor switches to supervisor mode.  During this transition, the address of the normal instruction that is executing is put into SRR0, and execution jumps to an interrupt handler.  If no interrupt happens, SRR0 is not updated.