On the safety of registers

Started by dcx2, July 31, 2010, 07:51:42 PM

Previous topic - Next topic

dcx2

Since it requires some knowledge about programming, this article might be too difficult to understand.  If that is the case, just put the following at the beginning/end of your ASM code.  This is all that you need...you don't need anything else from this article.  But don't change the first two or last two lines.

stwu r1,-80(r1)         # make space for 18 registers
stmw r14,8(r1)         # push r14-r31 onto the stack

# put your ASM code here
# you can safely use r14-r31

lmw r14,8(r1)         # pop r14-r31 off the stack
addi r1,r1,80         # release the space

---

In case you're thirsty for more...

The first part is a simple Function Prologue.  When we run out of registers, we use the stack to store some of them.  The stack is just a chunk of memory; you can look at it in Memory Viewer.  http://wiird.l0nk.org/forum/index.php/topic,6555.msg56574.html#msg56574

We can make room on the stack by "claiming" a chunk of it using stwu, which will also subtract from the stack pointer (in our case, we subtract 80).  It is extremely important that you follow the conventions when using the stack; failure to do so will almost certainly lead to crashes.

stmw is "STore Multiple Words".  It writes each register, starting with the source operand (r14 in our case), to subsequent addresses in memory, starting with the base-displacement operand, 8(r1) in our case.

At this point, it's safe to use any register from r14 up.  They're all stored on the stack, so you won't destroy their values.  Note that r14 is the first non-volatile register...there's very little reason to use any register below r14 with stmw.

The last part is a simple Function Epilogue.  It restores the contents to the registers from the stack.  lmw = Load Multiple Words, and it does pretty much the opposite of stmw.  Then, the amount of space that we subtracted from the stack pointer (in our case, 80) is added back to it.  This releases our claim on that chunk of the stack.

---

However, what if you don't want to add those four lines to all your ASM codes?  No code should ever require a stack frame...the PowerPC is a register-rich RISC architecture with 9 volatile registers (r0, r5-r12) that are safe after any bl.  If you learn to think like the compiler, you will see that there is always a bunch of free registers.

Register safety is a very, very elaborate subject.  To start, you should go here http://www.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf and save that file to your hard drive.  It is a super awesome reference!  <3 datasheets

---

I also made a pretty picture that might help illustrate volatile/nonvolatile registers across function calls.



A function is a Black Box.  Parameters go in, stuff gets processed, and outputs are returned.

There are two sides to a function; the call into it and the return from it.  Functions are called with bl (on the left), and functions return with blr (on the right).  All games follow a very specific convention when calling and returning from functions.

1) The caller (on the left side, outside the box) will not rely on volatile registers (the top half, r0-r12) to contain their previous values when execution returns from the function call (on the right side, outside the box).  Therefore, the callee is not required to protect their values.
2) However, the callee (inside the box) must preserve the values in the non-volatile registers (r13-r31) at the edges of the box.  This provides the illusion to the caller of stable, reliable values that persist after calling another function.  Note that callee may back up some of these registers and use them for its own function calls, but it must restore the original values before execution returns; this is denoted by the ... connecting left side of the box to the right side.
3) r31-r14 can be thought of as local variables.  If you see any of these registers being used, search only within the scope of the current function (from beginning to end, over bl if necessary) to see where the value comes from.
4) Note the black arrow pointing from r31 toward r14; games prefer larger registers.  This is also reflected in the architecture of the CPU, with the lmw and stmw instructions that load/store all the registers from r31 to the operand.
5) When calling a function with bl, the values in the blue registers on the left will be considered lost.  That is, at the very start of a function, in the new frame, r0/r11/r12 are safe to use.
6) When returning from a function with blr, the values in the blue registers on the right will be considered lost.  That is, after execution returns from a function to the caller's frame, the caller can safely use r0/r5-r12 (!!!).  This means that any hook which runs right below a bl can use nine registers safely.
7) Dark green registers on the left side are inputs.  You will see them loaded with values before a bl happens.  Games prefer small registers, so they'll start with r3 and work their way up.  If you know it only uses r3-r5, then you know that r6-r12 are safe at the start of the new function.  You also know that r6-r12 are also safe in the previous function, up to the previous bl (because they're volatile)
8 ) If you see these input registers being used, you only have to search as far back as the previous bl (because they are volatile)
9) However, because they are inputs, there may not be a "previous bl" before you walk past the very beginning of the function.  In this case, the value was passed in by the caller, so you must go back to the caller's frame to see where it got the values that it put into the parameters.
10) Bright green registers are outputs.  You will see them loaded before the blr.  There are only two, and the game prefers smaller registers again.  If you see these registers used, you may have to go into the called function to see where the values came from.
11) Don't use the bright red registers.  Ever.  Period.  Don't even try to back them up.  I warned you.

---

"Safe" is a colloquial phrase used to refer to a register whose contents can be over-written without ever affecting the game's execution.  Many 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.

Safe means that you can load a value into a register, and the original game code will over-write that value before reading from that register.  "Safety" changes over the course of execution; a register will be unsafe for a while, then it will become safe, and then unsafe again, over and over.

---

the Spectrum of Safety

safest --- safer --- safe --- ?? --- unsafe --- unsafer --- unsafest
r12   r11   r10-r5     r4-r3     r0       r31-r?       r14-r31    r1    r2,r13

---

There are two absolute ends to the Spectrum of Safety: "safest"/"unsafest".  There are a few special registers that are always/never safe to write to.

The safest register is r12.  r12 is used exclusively (at least to my knowledge) to load the ctr preceding a bctr[l]; this means there's only a one-instruction long "unsafe" window and it's very rare to encounter.  Unusual, but quite fortunate for us.  You pretty much never have to worry about the contents of r12.

Conversely, there are the unsafest registers r2 and r13.  NEVER EVER write to an unsafest register (you CAN still read).  There are no exceptions, period.  These registers are used by the CPU to access specific areas of memory related to constants, global variables, etc.  They will be read during interrupts which you will not see or know about.

---

Somewhat more nebulous to define are the safer/unsafer registers.  These have special conditions that affect their safety.

r1 is the most "unsafer" register.  Generally, you should consider it an unsafest register, but there are a few exceptions, but you have to follow a certain convention when writing to it.  It's possible that we can use "negative stack frames" for storing registers, but I don't know how to prove that negative stack frames are safe...

The regular unsafer registers are the non-volatile registers, r14-r31.  These registers must have their contents preserved if you write to them, with the exception of "temporal safety" where they may be safe for a brief period of execution.  In general, push/pop them on the stack or leave them alone.

---

To discuss the "safer" (aka volatile) registers, you will need to understand the concepts of a function call, parameter passing, and return registers.  You will need to know how bl/blr work, too.

r11 is the most safer register.  I think I have only ever seen r11 used to cache the stack pointer.  It is never used to pass parameters into a function, so it is safe after a bl (i.e. at the entry point of a function).  The function called does not have to preserve its contents, so it is guaranteed to be safe after a blr.

The other safer registers are r5-r10.  These are used to pass parameters into a function, so they are not safe after a bl.  In fact, if you see r5-r10 being written to, the game is probably getting ready to bl to a function.  However, these registers are NOT used to return values, so they are safe after a blr.

---

The unsafe registers start with r31 and extend backwards from there.  The compiler prefers larger registers, so you will usually see it start with r31, then r30/r29/etc.  EDIT: You can also see this preference reflected in the instructions lmw and stmw.

At the beginning of function calls (just after the bl), you will see the game push unsafe registers onto the stack.  This is the function preserving non-volatile registers, so that those registers can be used as local variables.  At the end of the function they will be popped off the stack.  EDIT: It is important to use non-volatile registers for storing the local variables, because the value in a non-volatile register persists across function calls.  Any value stored in a volatile register can/will be lost when a function is called.

The safe registers are r3 and r4.  Like r5-r10, these registers are used to pass parameters in.  The compiler prefers smaller registers, so you usually see r3, then r4, before r5/etc.  Unlike r5-r10, these registers are also used to pass return values back to the caller after a blr, again preferring smaller registers.  So they are NOT safe after a blr.

r0 is a special kind of safe.  It's almost safer; it is volatile, thus does not need preserved.  It is not used to pass parameters or return values, so it is safe after bl and blr like r11 and r12.  However, you cannot use r0 for rA in certain instructions (e.g. addi rD,rA,1).  These instructions will have "(rA|0)" in their datasheet describing their operation.  Other instructions that show only "rA" can use r0.  You can also use r0 for any other register operand (e.g. rD, rB, etc).

---

Unsafe registers, safe registers, and safer registers (when used) all have tempory windows of safety.  These are periods where the contents of the register do not matter; the game will not be reading from that register until after it has written a new value to it.

The top edge of a safe window is defined by the last instruction that read the contents of the register.  The bottom edge of the safe window is defined by the first instruction to write to the contents of the register.  During the safe window, a register is safe to use in your hook.

---

I put the examples in a separate post, because they take up too much space.  Go here to see them.  http://wiird.l0nk.org/forum/index.php/topic,6555.msg56577.html#msg56577

Deathwolf

#1
and now in german please lol
no just a joke... I think this is a tut for using other registers right?
lolz

Dude

That was a fantastic read!  And thankyou for the datasheet   :D

I was just looking deeper into things of this nature, too.  Could I download your brain? :p

Again, thanks for the indepth detailing of the registers, and also for the examples.  I'll be referring back to this on a regular basis.

dcx2

#3
I'd like to add a depiction of the spectrum of safety (also added to first post)

safest --- safer --- safe --- ?? --- unsafe --- unsafer --- unsafest
r12   r11   r10-r5     r4-r3     r0       r31-r?       r14-r31    r1    r2,r13


EDIT:

If I could share my brain, I would... :)  but it took a lot of work and education.  I've been programming for 15 years now.

Yes, Deathwolf, this is sort of a tutorial on how to determine if a register is safe to use in a C2 code without backing up the contents

dcx2

#4
(added to first post)

Since it requires some knowledge about programming, this article might be too difficult to understand.  If that is the case, just put the following at the beginning/end of your ASM code.  This is all that you need...you don't need anything else from this article.

stwu r1,-80(r1)         # make space for 18 registers
stmw r14,8(r1)         # push r14-r31 onto the stack

# put any ASM code here (C2, C0, etc)
# you can safely use r14-r31

lmw r14,8(r1)         # pop r14-r31 off the stack
addi r1,r1,80         # release the space

---

In case you're thirsty for more...

The first part is a simple Function Prologue.  When we run out of registers, we use the stack to store some of them.  The stack is just a chunk of memory; you can look at it in Memory Viewer.  We can make room on the stack by "claiming" a chunk of it using stwu, which will also subtract from the stack pointer (in our case, we subtract 80).  It is extremely important that you follow the conventions when using the stack; failure to do so will almost certainly lead to crashes.

stmw is "STore Multiple Words".  It writes each register, starting with the source operand (r14 in our case), to subsequent addresses in memory, starting with the base-displacement operand, 8(r1) in our case.

At this point, it's safe to use any register from r14 up.  They're all stored on the stack, so you won't destroy their values.  Note that r14 is the first non-volatile register...there's very little reason to use any register below r14 with stmw.

The last part is a simple Function Epilogue.  It restores the contents to the registers from the stack.  lmw = Load Multiple Words, and it does pretty much the opposite of stmw.  Then, the amount of space that we subtracted from the stack pointer (in our case, 80) is added back to it.  This releases our claim on that chunk of the stack.

---

However, what if you don't want to add those four lines to all your ASM codes?  No code should ever require a stack frame...the PowerPC is a register-rich RISC architecture with 9 volatile registers (r0, r5-r12) that are safe after any bl.  If you learn to think like the compiler, you will see that there is always a bunch of free registers.

AlexWong

Why the first line is stwu r1,-80(r1) instead of subi r1,r1,80? ???
Unsatisfied w/o cheats.

dcx2

Good question.  The reason is that stack frame convention I mentioned earlier.  You MUST be very careful to follow it.

You're required to store the current stack pointer at the top of the space you claimed.  Therefore, each stack frame will have a pointer to the previous stack frame.  This creates a Linked List, allowing you to access any stack frame no matter how big or small, by following the chain of pointers at 0(r1).

It's very important that you use stwu.  You must simultaneously store the stack pointer *and* subtract from it.  It must happen in a single instruction; it must be atomic in its execution.  If you were to separate it into two instructions, an interrupt could happen between the two, and this could corrupt the stack and crash your game.

Panda On Smack

Wow, thanks man

I wish you could share your brain as well!

hetoan2

this whole page could be added to the wiki :o


Check out my site with codes obviously...
http://hetoan2.com/

and youtube...
http://youtube.com/hetoan2

AlexWong

Unsatisfied w/o cheats.

dcx2

#10
Here's an example of a series of stack frames.  I've colored each frame so they stand out more.  This is just to stress that stack frames are just chunks of memory...I'll go into greater detail about stack frames later.  For now, understand that each stack frame is a step along a walk of the call stack.  Each function has called a subsequent function, which in turn called another, and so on; six times in total for this screenshot.  Think of it as six of the function boxes below, each frame inside each other like a Matryoshka doll


Deathwolf

#11
what happen if you write:

stwu r1,-80(r1)         # make space for 18 registers
stmw r0,8(r1)         # push r0-r31 onto the stack

# put your ASM code here
# you can safely use r0-r31

lmw r0,8(r1)         # pop r0-r31 off the stack
addi r1,r1,80         # release the space


push r0-r31 onto the stack.
use all registers. I think this will NEVER work....

lolz

dcx2


EXAMPLES

Here is an example from Super Mario Galaxy 2.  I was trying to find 1ups, so I found Mario's life count and set a write breakpoint on it, then got a 1up and backtracked in search of a 1up pointer.  Here's a small function I found while walking the stack.

804DE030:  9421FFF0   stwu   r1,-16(r1)   allocate room on the stack
804DE034:  7C0802A6   mflr   r0           preserve LR in r0
804DE038:  38A00063   li   r5,99          prepare r5 for the bl
804DE03C:  90010014   stw   r0,20(r1)     push LR onto the stack so we can bl
804DE040:  93E1000C   stw   r31,12(r1)    push r31 on the stack...
804DE044:  7C7F1B78   mr   r31,r3         ...so we can cache the pointer (parameter in r3) in r31
804DE048:  88030008   lbz   r0,8(r3)      read Mario's life count
804DE04C:  7C602214   add   r3,r0,r4      add the number of lives from parameter r4 to prepare r3 for the bl
804DE050:  38800000   li   r4,0           prepare r4 for the bl
804DE054:  4BB3BDAD   bl   0x80019e00     calls the function I breakpointed inside; makes sure r4 <= r3 <= r5; returns result in r3
804DE058:  987F0008   stb   r3,8(r31)     store the result returned from the function
804DE05C:  83E1000C   lwz   r31,12(r1)    pop the local variable's contents back into r31
804DE060:  80010014   lwz   r0,20(r1)     pop the LR back into r0
804DE064:  7C0803A6   mtlr   r0           restore LR so we can go back to our caller
804DE068:  38210010   addi   r1,r1,16     free the memory we allocated on the stack
804DE06C:  4E800020   blr                 return to caller


Notice how r3 and r4 were used to pass parameters into this function.  r3, r4, and r5 are used to pass parameters to the bl.  That bl used r3 to return a value.  r31 was used for a local variable, so it was pushed onto the stack.

---

I have bolded the window edges in this example.  r5 is ambiguous at the start of the function; it could be passing a parameter in.  However, it is written to before being read, so we can conclude that there is no important value in it.

804DE030:  9421FFF0   stwu   r1,-16(r1)
804DE034:  7C0802A6   mflr   r0
804DE038:  38A00063   li   r5,99
804DE03C:  90010014   stw   r0,20(r1)

As it turns out, 804DE038 is still safe.  This is because when you write a C2 hook, you always make sure to add the instruction you will replace to the end of your hook.  Your hook is effectively inside the window's bottom edge even if you are hooking the bottom edge.

r5 is now in an unsafe window from 804DE03C on.  The bottom edge of the window is defined by the bl at 804DE054; we CANNOT hook the bottom edge of unsafe windows.

804DE038:  38A00063   li   r5,99
804DE03C:  90010014   stw   r0,20(r1)
804DE040:  93E1000C   stw   r31,12(r1)
804DE044:  7C7F1B78   mr   r31,r3
804DE048:  88030008   lbz   r0,8(r3)
804DE04C:  7C602214   add   r3,r0,r4
804DE050:  38800000   li   r4,0
804DE054:  4BB3BDAD   bl   0x80019e00
804DE058:  987F0008   stb   r3,8(r31)

After the bl, r5 is safe again, through the blr.

804DE054:  4BB3BDAD   bl   0x80019e00
804DE058:  987F0008   stb   r3,8(r31)
804DE05C:  83E1000C   lwz   r31,12(r1)
804DE060:  80010014   lwz   r0,20(r1)
804DE064:  7C0803A6   mtlr   r0
804DE068:  38210010   addi   r1,r1,16
804DE06C:  4E800020   blr


---

The final product would look like this without the overlapping window edges

804DE030:  9421FFF0   stwu   r1,-16(r1)
804DE034:  7C0802A6   mflr   r0
804DE038:  38A00063   li   r5,99

804DE03C:  90010014   stw   r0,20(r1)
804DE040:  93E1000C   stw   r31,12(r1)
804DE044:  7C7F1B78   mr   r31,r3
804DE048:  88030008   lbz   r0,8(r3)
804DE04C:  7C602214   add   r3,r0,r4
804DE050:  38800000   li   r4,0
804DE054:  4BB3BDAD   bl   0x80019e00

804DE058:  987F0008   stb   r3,8(r31)
804DE05C:  83E1000C   lwz   r31,12(r1)
804DE060:  80010014   lwz   r0,20(r1)
804DE064:  7C0803A6   mtlr   r0
804DE068:  38210010   addi   r1,r1,16
804DE06C:  4E800020   blr


---

Let's look at r4.  r4 is passing a parameter in, so it is in an unsafe window from the start of the function until the last read before the first subsequent write.

804DE030:  9421FFF0   stwu   r1,-16(r1)
804DE034:  7C0802A6   mflr   r0
804DE038:  38A00063   li   r5,99
804DE03C:  90010014   stw   r0,20(r1)
804DE040:  93E1000C   stw   r31,12(r1)
804DE044:  7C7F1B78   mr   r31,r3
804DE048:  88030008   lbz   r0,8(r3)
804DE04C:  7C602214   add   r3,r0,r4      last read

804DE050:  38800000   li   r4,0              first subsequent write
804DE054:  4BB3BDAD   bl   0x80019e00   r4 used as parameter
804DE058:  987F0008   stb   r3,8(r31)   
804DE05C:  83E1000C   lwz   r31,12(r1)
804DE060:  80010014   lwz   r0,20(r1)
804DE064:  7C0803A6   mtlr   r0
804DE068:  38210010   addi   r1,r1,16
804DE06C:  4E800020   blr


It's possible the bl is returning something in r4, and that value is returned by us without modification.  So I would declare the region after the bl to be an unsafe window for r4.  If you knew the bl didn't load anything into r4, then you could probably use it here.  This is why r5-r10 are safer than r3 and r4.

---

r3 is even more fun!  It starts off as a parameter, then it is used as a different parameter, then it has a return value, and then it's ambiguous!

804DE030:  9421FFF0   stwu   r1,-16(r1)
804DE034:  7C0802A6   mflr   r0
804DE038:  38A00063   li   r5,99
804DE03C:  90010014   stw   r0,20(r1)
804DE040:  93E1000C   stw   r31,12(r1)
804DE044:  7C7F1B78   mr   r31,r3
804DE048:  88030008   lbz   r0,8(r3)

804DE04C:  7C602214   add   r3,r0,r4
804DE050:  38800000   li   r4,0
804DE054:  4BB3BDAD   bl   0x80019e00
804DE058:  987F0008   stb   r3,8(r31)
804DE05C:  83E1000C   lwz   r31,12(r1)
804DE060:  80010014   lwz   r0,20(r1)
804DE064:  7C0803A6   mtlr   r0
804DE068:  38210010   addi   r1,r1,16
804DE06C:  4E800020   blr


---

r31 is safe once it is pushed onto the stack, until it is loaded with the copy of the pointer.  It's then safe after the pointer is used, until the original contents are popped off the stack.

804DE030:  9421FFF0   stwu   r1,-16(r1)
804DE034:  7C0802A6   mflr   r0
804DE038:  38A00063   li   r5,99
804DE03C:  90010014   stw   r0,20(r1)
804DE040:  93E1000C   stw   r31,12(r1)

804DE044:  7C7F1B78   mr   r31,r3
804DE048:  88030008   lbz   r0,8(r3)
804DE04C:  7C602214   add   r3,r0,r4
804DE050:  38800000   li   r4,0
804DE054:  4BB3BDAD   bl   0x80019e00
804DE058:  987F0008   stb   r3,8(r31)

804DE05C:  83E1000C   lwz   r31,12(r1)
804DE060:  80010014   lwz   r0,20(r1)
804DE064:  7C0803A6   mtlr   r0
804DE068:  38210010   addi   r1,r1,16
804DE06C:  4E800020   blr


---

r0's safety is awkward.  Don't forget that it can't be used as rA for many instructions, too.

804DE030:  9421FFF0   stwu   r1,-16(r1)
804DE034:  7C0802A6   mflr   r0

804DE038:  38A00063   li   r5,99
804DE03C:  90010014   stw   r0,20(r1)

804DE040:  93E1000C   stw   r31,12(r1)
804DE044:  7C7F1B78   mr   r31,r3
804DE048:  88030008   lbz   r0,8(r3)

804DE04C:  7C602214   add   r3,r0,r4
804DE050:  38800000   li   r4,0
804DE054:  4BB3BDAD   bl   0x80019e00
804DE058:  987F0008   stb   r3,8(r31)
804DE05C:  83E1000C   lwz   r31,12(r1)
804DE060:  80010014   lwz   r0,20(r1)

804DE064:  7C0803A6   mtlr   r0
804DE068:  38210010   addi   r1,r1,16
804DE06C:  4E800020   blr


---

The remaining safer registers (r6-r10 + r11) are safe from start to finish.  As you can see, they are never used.

The remaining unsafer registers (r14-r30) are never safe.  If you wish to use any of these registers, you MUST preserve the contents in a stack frame.

As always, r12 is always safe, and r2/r13 are never safe even if you try to preserve the contents.

When writing codes, if you need a lot of registers, try to hook an address that has as many overlapping windows of safety as possible.

dcx2

(added to first post)

I also made a pretty picture that might help illustrate volatile/nonvolatile registers across function calls.



A function is a Black Box.  Parameters go in, stuff gets processed, and outputs are returned.

There are two sides to a function; the call into it and the return from it.  Functions are called with bl (on the left), and functions return with blr (on the right).  All games follow a very specific convention when calling and returning from functions.

1) The caller (on the left side, outside the box) will not rely on volatile registers (the top half, r0-r12) to contain their previous values when execution returns from the function call (on the right side, outside the box).  Therefore, the callee is not required to protect their values.
2) However, the callee (inside the box) must preserve the values in the non-volatile registers (r13-r31) at the edges of the box.  This provides the illusion to the caller of stable, reliable values that persist after calling another function.  Note that callee may back up some of these registers and use them for its own function calls, but it must restore the original values before execution returns; this is denoted by the ... connecting left side of the box to the right side.
3) r31-r14 can be thought of as local variables.  If you see any of these registers being used, search only within the scope of the current function (from beginning to end, over bl if necessary) to see where the value comes from.
4) Note the black arrow pointing from r31 toward r14; games prefer larger registers.  This is also reflected in the architecture of the CPU, with the lmw and stmw instructions that load/store all the registers from r31 to the operand.
5) When calling a function with bl, the values in the blue registers on the left will be considered lost.  That is, at the very start of a function, in the new frame, r0/r11/r12 are safe to use.
6) When returning from a function with blr, the values in the blue registers on the right will be considered lost.  That is, after execution returns from a function to the caller's frame, the caller can safely use r0/r5-r12 (!!!).  This means that any hook which runs right below a bl can use nine registers safely.
7) Dark green registers on the left side are inputs.  You will see them loaded with values before a bl happens.  Games prefer small registers, so they'll start with r3 and work their way up.  If you know it only uses r3-r5, then you know that r6-r12 are safe at the start of the new function.  You also know that r6-r12 are also safe in the previous function, up to the previous bl (because they're volatile)
8 ) If you see these input registers being used, you only have to search as far back as the previous bl (because they are volatile)
9) However, because they are inputs, there may not be a "previous bl" before you walk past the very beginning of the function.  In this case, the value was passed in by the caller, so you must go back to the caller's frame to see where it got the values that it put into the parameters.
10) Bright green registers are outputs.  You will see them loaded before the blr.  There are only two, and the game prefers smaller registers again.  If you see these registers used, you may have to go into the called function to see where the values came from.
11) Don't use the bright red registers.  Ever.  Period.  Don't even try to back them up.  I warned you.

wiiztec

Can you write a guide like this for floating point registers?
If there's any code at all that you want to be button activated, or even able to toggle on & off, and I have the game, just PM me and I'll make it happen