Super Mario Galaxy 2 Multi-Teleporter/Levitation v2 details

Started by dcx2, July 24, 2010, 11:13:45 PM

Previous topic - Next topic

dcx2

Here's the disassembly and notes for the code here http://wiird.l0nk.org/forum/index.php/topic,5791.msg55338.html#msg55338

There are a lot of ASM techniques I used here...it's pretty epic in scope.  It's my hope that others can learn from these techniques so they may write better ASM hacks.  Feel free to ask questions about it.  It can be quite difficult to digest, though, so if there's enough interest I can show how the ASM code evolved from the first successful teleportation until this final code.

EDIT: Since posting this, I've managed to optimize two more instructions out, making it one line shorter.


Hook 803880AC = lwz r0,52(r1)
r3 has coordinates to read/write
r0,r30,r31 safe
controller at 80750A00
button offset = 2
Y axis offset = 100
xyz orientation offset = 12/16/20
b+z+[other] to store, b+[other] to restore
32.0 = 42000000


The following can be put straight into PyiiASMH.  Use the hook address above.

# -------------- VARIABLES --------------
# to optimize an ori, we'll add the low hword of the controller address to all the offsets
.set CONTROLLER_ADDRESS_LOW,0xA00
.set BUTTON_OFFSET,2+CONTROLLER_ADDRESS_LOW
.set XYZ_ORIENT_OFFSET,12+CONTROLLER_ADDRESS_LOW
.set YAXIS_OFFSET,100+CONTROLLER_ADDRESS_LOW

.set FLOAT_OFFSET,FLOAT_POINTER_OFFSET-DATA_POINTER_BASE
.set B_MASK,0x400
.set Z_MASK,0x2000

# -------------- CODE --------------

lis r12,0x8075   # load the controller pointer 8075 into r12

# bl here so that the data area is 64-bit aligned close to the front of the C2 code
# bl will simultaneously skip over the data area
# *and* put a pointer to the data in LR
bl SKIP_DATA

DATA_POINTER_BASE:
# the four coordinate slots are stored here
# they are accessed by indexing off the data pointer
# note that each line is 96 bits; 32 bits each for X, Y, and Z
.long 0,0,0
.long 0,0,0
.long 0,0,0
.long 0,0,0
FLOAT_POINTER_OFFSET:
.long 0x42000000   # the max levitation speed, 32.0 in decimal

SKIP_DATA:
lhz r30,BUTTON_OFFSET(r12)   # load button values into r30
andi. r0,r30,B_MASK   # mask off the bit for the B button
beq- THE_END   # eq means B is not being held down, so exit the code

rlwinm. r0,r30,28,0,3 # mask off the index buttons, rotate the interesting bits to the front
beq- THE_END   # eq means no index buttons held, so exit the code

cntlzw r0,r0      # convert it to an index
mulli r0,r0,12      # multiply by 12 bytes per index to get an offset

mflr r31      # grab data pointer from LR

# r30 still has controller values, but those aren't needed after this test
# r31 has data pointer
# r0 has offset
andi. r30,r30,Z_MASK
add r30,r31,r0      # r30 now has pointer to indexed data coords
beq- RESTORE   # eq means z not held, so load data coords

STORE:
# r3 is source
# r30 already has destination (data coords pointer)
# r12 is now free
mr r12,r3
b MEMCPY

RESTORE:
LEVITATE:
# r31 has pointer to data
# r12 still has controller pointer
# r30 has pointer to data coords
lfs f0,FLOAT_OFFSET(r31)
lfs f1,YAXIS_OFFSET(r12)
# f0 has max speed float stored in data area
# f1 has the value of the Y axis from p1's nunchuck
fmuls f0,f0,f1      # scale = max speed * Y axis

# set up a loop
# note that lfsu requires pointing 4 bytes _before_ the first value
li r0,3
mtctr r0
addi r31,r12,XYZ_ORIENT_OFFSET-4
subi r12,r30,4      # work on a cached copy of r30

# f0 has the scale value
# r31 has p1 wiimote orientation pointer
# r12 has a pointer to code's stored coordinates
TOP_OF_LOOP:
lfsu f1,4(r31)
lfsu f2,4(r12)
fnmsubs f1,f0,f1,f2   # f1 = coords â€" (scale * orientation)
stfs f1,0(r12)
bdnz+ TOP_OF_LOOP


# r30 is source, r3 is dest
mr r12,r30
mr r30,r3

MEMCPY:
# r12 is source, r30 is dest
psq_l f0,0(r12),0,0
psq_l f1,8(r12),1,0
psq_st f0,0(r30),0,0
psq_st f1,8(r30),1,0

THE_VERY_END:
THE_END:
lwz r0,52(r1)

Deathwolf

wow that's crazy but very nice ASM instructionen :eek:
you included again a button activator with button address in your asm code.
how to do this? you said, blackwolf's tut fails because he forgot the alignment.

full code:
lis r12,-32651
ori r12,r12,2560
lhz r30,2(r12)
andi. r0,r30,1024
beq- 0x78
rlwinm. r0,r30,19,9,12
beq- 0x70
cntlzw r0,r0
mulli r0,r0,12
bl 0x04
mflr r31
andi. r30,r30,8192
add r30,r31,r0
beq- 0x0C
mr r12,r3
b 0x3C
lfs f0,104(r31)
lfs f1,100(r12)
fmuls f0,f0,f1
li r0,3
mtctr r0
addi r31,r12,8
subi r12,r30,4
lfsu f1,4(r31)
lfsu f2,4(r12)
fnmsubs f1,f0,f1,f2
stfs f1,0(r12)
bdnz+ 0xFFFFFFF0
mr r12,r30
mr r30,r3
psq_l f0,0(r12),0,0
psq_l f1,8(r12),1,0
psq_st f0,0(r30),0,0
psq_st f1,8(r30),1,0
lwz r0,52(r1)
b 0x38
bdnz- 0x00
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
lolz

Bully@Wiiplaza

Why do you use the 00000000 lines?
Aren´t they useless, that´s what I am wondering :eek:
My Wii hacking site...
http://bullywiihacks.com/

My youtube account with a lot of hacking videos...
http://www.youtube.com/user/BullyWiiPlaza

~Bully

dcx2

Quote from: Deathwolf on July 25, 2010, 11:28:57 AM
you included again a button activator with button address in your asm code.
how to do this? you said, blackwolf's tut fails because he forgot the alignment.

If you look at the top, the line that says .set BUTTON_OFFSET,2 creates a variable and further down is another line that says lhz r30,BUTTON_OFFSET(r12).  This is how I preserved alignment.  I did this because I needed the controller pointer in order to get the Y axis and Wiimore orientations.  You can see their offsets declared at the top, too, as YAXIS_OFFSET and XYZ_ORIENT_OFFSET.

---

Quote from: Bully@Wiiplaza on July 25, 2010, 12:26:56 PM
Why do you use the 00000000 lines?
Aren´t they useless, that´s what I am wondering :eek:

That is where the coordinates are stored.  I call it a "Small Data Area" because the data's embedded in the C2 code.  Each .long 0,0,0 is a set of XYZ coordinates, and there are four sets, one for each slot.  I get a pointer to the SDA by using a technique I saw in brkirch's moon jump.  blr 4/mflr.

Deathwolf

yea but there is no example how to use beq- 0xXX, andi. rX,rXX,XXXX or something other instructionen...
then the alignment is confusing me. Sometimes I'm not sure, if my C2 codes are wrong!?

Yes for you it's maybe very easy and you can make alot of C2 codes with more than 20 instructionen,but for some other it's too hard without any examples...
I know it's maybe also hard for you to explain it right and you try to help everyone but some hackers haven't a chance and can't learn someting new without any examples.
BUT I hope you know that I'm very grateful to you....
lolz

dcx2

I posted this so people can ask questions about how it works.  There is a lot of reasoning behind every line, and sometimes there's lots of reasons behind a single line.  Think of it as a "living tutorial"; rather than me telling you how it works, you should find a part that you want to learn about and ask why/what it does.

I can also start at the beginning, with the unoptimized single teleporter.  That way you can see how the code "grows", like a flower, into something more complex.

---

Do you understand beq- at all, or why beq- is used with andi.?

andi. = AND with Immediate.  The AND operation is used to "mask" off the interesting bit.

At the top, I declared Z_MASK = 0x2000 and B_MASK = 0x400.  These masks go over-top of the buttons and hide everything else.  This allows me to see whether or not the Z button is pressed while ignoring the other buttons.

The AND operation tells me the result by setting or clearing bits in the Condition Register (CR).  You can see the CR on the Breakpoint tab.  The first bit (from the left) is equals, the second is greater than, and the third is less than.

If the result of an AND is equal to 0, then the equals bit of the CR is set to 1.  If the result is not equal to 0, then the equals bit is cleared to 0.

When beq- is encountered, the processor will check the equals bit of the CR.  If it is set, it will branch to the destination.  If the equals bit of the CR is clear, then the code does NOT branch, but instead goes on to the next instruction.  (Notice that I use branch labels instead of numbers; PyiiASMH will calculate offsets for you using the labels)

If you follow this post, you can see an example where I color-coded the instructions that get executed with a beq-.  http://wiird.l0nk.org/forum/index.php/topic,5836.msg50772.html#msg50772

Deathwolf

u mean andi is a if code?

andi. r0,r30,0x2000 <-- write value 2000 to the button address?
beq- 0x78 <-- check it if the button Z pressed and branch it?if not,code is disabled?
lolz

dcx2

(EDIT: Yes, andi. and beq- are one way to do an if code)

andi. does a bit mask.  Like holding up a piece of paper, with holes where there are 1's in the bit mask.

The mask will hide the blue squares that we aren't interested in, and only show us what is behind the red squares.

Let's say you're holding b + up arrow.  This is 0x408.  The B_MASK is 0x400.  In binary, it would look like this
0000 0100 0000 1000 # button values (in r30)
0000 0100 0000 0000 # B_MASK (the Immediate)
__________________  # AND
0000 0100 0000 0000 # result (written to r0)

Compare to Z_MASK = 0x2000

0000 0100 0000 1000 # button values
0010 0000 0000 0000 # Z_MASK
__________________  # AND
0000 0000 0000 0000 # result

---

In the first case, the result written to r0 is not equal to 0.  So the equals bit of the CR will be cleared to 0.

In the second case, the result written to r0 is equal to 0.  So the equals bit of the CR will be set to 1.

Deathwolf

makes no sense for me!?
maybe I don't understand it or wrong....

I'm searching for a universal instruction for including button activator...
lolz

dcx2

There is no such thing as universal.  Banish the thought from your mind.  Even with regular WiiRD codes, but especially with ASM

There are two general types of button activators.

A) Is this the only button being pressed?  For example, 28750A02 00000408 = "is B and up but no other buttons"

B) Is this any of the buttons being pressed?  For example, 28750A02 FBF70408 = "is B and up, and whatever else"

---

In ASM, A will need cmpwi.  Only exact matches (b and up but nothing else)  B will use andi. because you don't care about other buttons.

Then you need to decide if you're doing bne- or beq-.

dcx2

This code uses the second type, B, of activator.  Let's take a closer look at the first section.

The intent of the code is to cause a teleportation when you do b button + any arrow, or to store coordinates if you do b + z + arrow.  So if there is no b, then there should be no hook.

# load r12 with a pointer to the controller values, 80750A00
lis r12,0x8075
ori r12,r12,0x0A00

# Add the BUTTON_OFFSET = 2 to the pointer 80750A00 in r12 and put the value at that address into r30
# r30 = [r12+BUTTON_OFFSET]
lhz r30,BUTTON_OFFSET(r12)

# Apply the B_MASK to r30, and put the result into r0
andi. r0,r30,B_MASK

# if the result of the mask is 0, the equals bit will be set
# this means b is not pressed
# but we only want to hook when b is pressed...
# ...so we branch to the end if the mask = 0
beq- THE_END

---

Later, there's another button activator for Z.  If we have B pressed, then we want to do something different depending on whether z is pressed or not.

# r30 still has the value of the buttons
andi. r30,r30,Z_MASK
...
# if the result was equal to 0, then z is not pressed, so load coordinates
beq- RESTORE

# otherwise, store coordinates
...etc...

Deathwolf

you said anything about cmpwi.
for what?
so this is it?

lis r12,-32651
ori r12,r12,2560
lhz r30,2(r12)
andi. r0,r30,1024
beq- 0x78

lis r12,-32651->3D808075 618C0A00 <- ori r12,r12,2560
lhz r30,2(r12) ->A3CC0002 73C00400 <-andi. r0,r30,1024
beq- 0x78      ->41820078


lis r12,0x8075
ori r12,r12,0x0A00
lhz r30,2(r12)
andi. r0,r30,0x0400 <-- B MASK
beq- 0x78 <-- END
lolz

dcx2

cmpwi is for different button activators.  Like 28 codes with the MMMM = 0000.  andi. is used for codes where MMMM != 0.

Yes, PyiiASMH automatically calculated that the branch distance from the beq- to THE_END was 0x78.  I didn't have to count that.

andi. was used to mask the buttons to see if B was pressed.

Deathwolf

that's a really nice instrucion!!
so you mean PyiiASMH calculate for me the branch distance from the beq- to end?
where can I get this nice tool? at the moment I only use ASM to wiird.

thanks alot dcx2.

btw is the code right?

lis r12,0x8075
ori r12,r12,0x0A00
lhz r30,2(r12)
andi. r0,r30,0x0400 <-- B MASK
beq- 0x78 <-- END
lolz