In the Super Mario Galaxy 2 code topic I posted commented disassembly of the moon jump code I created. However the problem with it was that the offsets used to access the data had to be calculated manually which can be a lot of work for longer codes (like the SMG2 transformation code I will be releasing soon, which has over 400 lines of assembly) and has to be done every time the code length changes. The solution I found was to rewrite the codes like this:
/* ASM insert for storing initial jump velocity */
.set codeaddress,0x803A2FE0
.set length,end1-start1
.set align,(length%8==0)*-0x60000000
.set numlines,(length+4)/8+(length%8==0)*-1
.set initialXoffset,initialX-offset1
.set initialYoffset,initialY-offset1
.set initialZoffset,initialZ-offset1
.set codereg1,3
.set codereg2,4
.int codeaddress<<7>>7|0xC2000000
.int numlines
start1:
bl 0x4 #move address of next instruction to LR (offsets off of that address will be used for storing initial jump velocity components within this code)
offset1:
mflr codereg2 #move LR to codereg2
lwz codereg1,724(r31) #read initial jump velocity x component
stw codereg1,initialXoffset(codereg2) #store a copy of initial jump velocity x component
lwz codereg1,728(r31) #read initial jump velocity y component
stw codereg1,initialYoffset(codereg2) #store a copy of initial jump velocity y component
lwz codereg1,732(r31) #read initial jump velocity z component
stw codereg1,initialZoffset(codereg2) #store a copy of initial jump velocity z component
lis r4,-32660 #execute instruction originally at this address
b end1 #skip section of code used for data
initialX:
.int 0x00000000 #initial jump velocity x component is stored here
initialY:
.int 0x00000000 #initial jump velocity y component is stored here
initialZ:
.int 0x00000000 #initial jump velocity z component is stored here
end1:
.int align
.balignl 8,0
/* ASM insert for replacing jump velocity with initial jump velocity */
.set codeaddress,0x80388E44
.set buttonsaddr,0x80750A00
.if buttonsaddr<<16>>16>=0x8000
.set buttonsaddrhigh,buttonsaddr>>16+1
.set buttonsaddrlow,buttonsaddr<<16>>16-0x10000
.else
.set buttonsaddrhigh,buttonsaddr>>16
.set buttonsaddrlow,buttonsaddr<<16>>16
.endif
.set length,end2-start2
.set align,(length%8==0)*-0x60000000
.set numlines,(length+4)/8+(length%8==0)*-1
.set initialXoffset,initialX-offset2
.set initialYoffset,initialY-offset2
.set initialZoffset,initialZ-offset2
.set codereg1,3
.set codereg2,4
.int codeaddress<<7>>7|0xC2000000
.int numlines
start2:
lis codereg2,buttonsaddrhigh
lwz codereg2,buttonsaddrlow(codereg2) #read address that contains current pressed buttons to codereg2
rlwinm. codereg2,codereg2,0,20,20 #check if button A is pressed
beq- endCode #if button A is not pressed, end code
bl 0x04 #move address of next instruction to LR (offsets off of that address will be used for reading initial jump velocity components contained within above C2 code)
offset2:
mflr codereg2 #move LR to codereg2
lwz codereg1,initialXoffset(codereg2) #read initial jump velocity x component
stw codereg1,724(r31) #replace current velocity x component with initial jump velocity x component
lwz codereg1,initialYoffset(codereg2) #read initial jump velocity y component
stw codereg1,728(r31) #replace current velocity y component with initial jump velocity y component
lwz codereg1,initialZoffset(codereg2) #read initial jump velocity z component
stw codereg1,732(r31) #replace current velocity z component with initial jump velocity z component
endCode:
mr r3,r31 #execute instruction originally at this address
end2:
.int align
.balignl 8,0
This assembly can then be put into a program like
PyiiASMH and the assembler will calculate ALL of the offsets, which not saves time but also reduces the chance of the code not working correctly due to human error (it is really easy to accidentally get an offset wrong and very hard to track down where mistakes like that are).
I found this again recently and was reminded of the awesomeness of some tricks here. For instance, you probably didn't notice, but brkirch is writing two C2 codes with his ASM, with one code reading the other code's data area! This requires using PyiiASMH in RAW mode. Amazing! Exactly what I was looking for myself.
However, I noticed one thing that reminded me of a Y.S. technique. Here is the piece in particular that I'm talking about in brkirch's assembly.
This trick is meant to handle sign-extension of the displacement operand. Y.S. noted via
http://www.ibm.com/developerworks/library/l-ppc/ that the @ha symbol can serve this purpose.
---
Using macros, it is possible to "extend" the ASM to make this re-usable. I call it "lwza" for "lwz absolute". It will load a 4-byte value from a full 4-byte address
.macro lwza reg1,address
lis \reg1, \address@ha
lwz \reg1, \address@l(\reg1)
.endm