Mario Kart Wii Gecko Codes, Cheats, & Hacks

Full Version: Utilizing the Condition Register
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Utilizing the Condition Register

For Advanced ASM Coders



Chapter 1: Intro

Requirements:
  • Understand the basics of using compare and branch instructions
  • Understand binary/bits + Logical Operations

Are your codes ending up with "countless" branches and branch labels? Your codes are in need of some spring cleaning. Sometimes codes that have an excessive amount branches end up "unreadable", making it difficult for others to understand your code or help you debug any errors.



Chapter 2: Condition Register Fundamentals

When you execute any plane jane comparison instruction such as....

Code:
cmpwi r0, 100

...you are actually telling Broadway to run a check and then place the result of said check in Condition Register Field 0.

What is Condition Register Field 0? First thing's first. The register you see in Dolphin that is named "CR" is the Condition Register. It contains the results of previously executed Compare Instructions. Conditional Branch Instructions (i.e. beq) read the data of the Condition Register to determine whether or not a branch route/jump is taken.

The Condition Register contains 7 fields. Field 0 (cr0) thru Field 7 (cr7).

STUVWXYZ

S = cr0
T = cr1
U = cr2
etc etc..

Each field (crF) takes up one DIGIT (half-byte) in the CR. Thus, each crF contains 4 bits of data. You can specify which crF to place the result of the compare instruction in. By default, if no crF is specified in your compare instruction, then cr0 will be used.

Code:
cmpwi r0, 100

is short for...

Code:
cmpwi cr0, r0, 100

If you wish to use cr7 instead of cr0, you would write the instruction like this...

Code:
cmpwi cr7, r0, 100

An important thing that you must keep in mind is that if you make a comparison that is NOT using cr0, you must also specify the crF in the subsequent branch instruction.

Like this...

Code:
cmpwi cr7, r0, 100
beq- cr7, store_data #Notice the specification of cr7 in the instruction

In conclusion, any crF that isn't cr0 must be specified in both compare and branch instructions.



Chapter 3: Condition Register Field Bits and Examining Branch Instructions

Now that you know there are 7 crF's and how to use each one in your comparison + branch instructions, let's cover the crF bits and what each bit represents.

Each crF has 4 bits of data that uses the following structure.
  • bit 0 = Less-Than flag (LT)
  • bit 1 = Greater-Than flag (GT)
  • bit 2 = Equal flag (EQ)
  • bit 3 = Summary Overflow flag (SO)

CR Bit Table
LT GT EQ SO  crfX
0  1  2  3  crf0
4  5  6  7  crf1
8  9 10 11  crf2
12 13 14 15  crf3
16 17 18 19  crf4
20 21 22 23  crf5
24 25 26 27  crf6
28 29 30 31  crf7

Whenever a bit in the crF is high, the condition was true FROM THE MOST RECENT comparison instruction. Whenever a bit was low, the condition was false FROM THE MOST RECENT comparison.

Multiple bits can be flagged high and/or low from a comparison instruction. Now that you understand the crF bits, let's go over what branch instructions actually do.

Code:
bge (branch if greater than or equal) = checks bits 1 and 2, if either bit is high, branch is taken
bgt (branch if greater than) = checks bit 1, if bit is high, branch is taken
ble (branch if less than or equal) = checks bits 0 and 2, if either bit is high, branch is taken
blt (branch if less than) = checks bit 0, if it is high, branch is taken
bne (branch if not equal) = checks bit 2, if bit is low, branch is taken
bng (branch if not greater than) = equivalent to ble
bnl (branch if not less than) = equivalent to bge
bns (branch if not summary overflow) = checks bit 3, if bit is low, branch is taken
bso (branch if summary overflow) = checks bit 3, if bit is high, branch is taken

The branch instruction checks the bits of the crF that is specified in the instruction.

Example: 'bge- cr7' checks GT and EQ bits of cr7



Chapter 4: Condition Register specific instructions

Before going into the CR specific instructions, we need to go over its 'format'. The 'format' of a typical CR instruction is this..

crXXX B, B, B #XXX = and, or, andc, orc, nor, xor, eqv

Under this format, you need to specify the exact bit of the entire Condtion Register. The problem with this is that it now becomes a memory game and you have to refer to the earlier CR bit table provided in Chapter 3. Instead of doing that non-sense, you can use this handy formula...

B = 4*crX+ZZ

X = field number (0 thru 7)
ZZ = lt, gt, eq, or so

With this formula, all you need to remember to which Field you want to use and what bit type. So now the easier-to-remember 'format' is this..

crXXX 4*crX+ZZ, 4*crX+ZZ, 4*crX+ZZ

---

CR Based Instructions:
  • Condition Register Logical OR~
    cror crfD, crfA, crfB #crfA bit is logically OR'd with crfB bit. Result is written to crfD bit.
  • Condition Register Logical AND~
    crand crfD, crfA, crfD #crfA bit is logically AND'd with crfB bit. Result is written to crfD bit.
  • Condition Register Logical NOR~
    crnor crfD, crfA, crfD #crfA bit is logically NOR'd with crfB bit. Result is written to crfD bit.
  • Condition Register Logical XOR~
    crxor crfD, crfA, crfD #crfA bit is logically XOR'd with crfB bit. Result is written to crfD bit.
  • Condition Register Logical EQV (XNOR)~
    creqv crfD, crfA, crfD #crfA bit is logically XNOR'd with crfB bit. Result is written to crfD bit. Technically, the instruction does a XOR of crfA with crfD, then this temp result is complemented, then writes that result to crfD.
  • Condition Register Logical AND with Complement~
    crandc crfD, crfA, crfD #crfA bit is logically AND'd with the complemented crfB bit. Result is written to crfD bit.
  • Condition Register Logical OR with Complement~
    crorc crfD, crfA, crfD #crfA bit is logically OR'd with the complemented crfB bit. Result is written to crfD bit.

Simplified Mnemonics:
  • Setting a bit high (set cr0 EQ high)~
    crset 4*cr0+eq #creqv 4*cr0+eq, 4*cr0+eq, 4*cr0+eq; crF bit is XNOR'd with itself and resutl written to same bit spot
  • Setting a bit low (set cr0 EQ low)~
    crclr 4*cr0+eq #crxor 4*cr0+eq, 4*cr0+eq, 4*cr0+eq; crF bit is XOR'd with itself and result written to same bit spot
  • Copy-Pasting (Moving) a bit (copy cr0 EQ bit to cr7 EQ bit's spot)
    crmove 4*cr7+eq, 4*cr0+eq #cror 4*cr7+eq, 4*cr0+eq, 4*cr0+eq; crF bit is Or'd with itself and result writen to crfD
  • Flip a bit (flip cr0 EQ bit and place result in cr7 EQ bit's spot))
    crnot 4*cr7+eq, 4*cr0+eq  #crnor 4*cr0+eq, 4*cr0+eq, 4*cr0+eq; crF bit is NOR'd with itself and result written to crfD

Also, the following instructions may be handy for you...
  • mfcr rD #Contents of the CR is copied to rD
  • mtcr rD #Contents of rD is copied to the CR
  • mcrf crD, crA #Condition Field A is copied to Condition Field D



Chapter 5: Cleaning up some Code

Let's go over some basic examples of some "CR trickery" to help clean up code. Some examples below won't shorten the source at all (will be same compiled length), but the amount of branches (plus label names) are reduced. This is accomplished by using multiple crF's and using Condition Register specific instructions.

Scenario 1:
If r4 = 1 and r10 = r31, then go to 'store_data'. Otherwise, go to 'dont_store'.

Typical Source
Code:
cmpwi r4, 1
bne- dont_store
cmpw r10, r31
beq- store_data

New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data

Scenario 2:
If r4 = 1 or r10 = r31, then go to 'store_data'. Otherwise, go to 'dont_store'.

Typical Source
Code:
cmpwi r4, 1
beq- store_data
cmpwi r10, r31
bne- dont_store

New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
cror 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data

Scenario 3:
If r4 = 1 and r10 =/= r31, then go to 'store_data'. Otherwise, end_code

Typical Source
Code:
cmpwi r4, 1
bne- end_code
cmpw r10, r31
bne- store_data

New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crandc 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data

Scenario 4:
If r4 = 1 or r10 =/= r31, then go to 'store_data'.

Typical Source
Code:
cmpwi r4, 1
beq- store_data
cmpw r10, r31
bne- store_data

New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crorc 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data

Scenario 5:
If r4 = 1 then r10 must =/= r31, or if r4 =/=1 then r10 must = r31. If all requirments met go to 'store_data'. If not, go to end_code.

Typical Source
Code:
cmpwi r4, 1
bne- make_sure_next_true

#r4 = 1, r10 must =/= r31
cmpw r10, r31
bne- store_data
b end_code

#r4 =/= 1, r10 must = r31
make_sure_next_true:
cmpw r10, r31
beq- store_data

New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crxor 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data

Scenario 6:
If r4 = 1, then r10 must = r31. However r4 can =/= 1 as long as r10 =/= r31. If all requirements are met go to 'store_data'. If not, go to end_code.

Typical source
Code:
cmpwi r4, 1
bne- make_sure_next_false

#r4 = 1, r10 must = r31
cmpw r10, r31
bne- store_data
b end_code

#r4 =/= 1, r10 must =/= r31
make_sure_next_false:
cmpw r10, r31
bne- store_data

New source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
creqv 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data



Chapter 6: Final Example

Let's say you have a value in r3 and it must be a valid Memory Address. Meaning a valid mem80, mem81, or mem9 address. If the address is not valid in any way, branch to the LR. An efficient way to write it would be like this (pretend r4 thru r7 are safe)...

Code:
lis r4, 0x8000 #0x80000000
lis r5, 0x817F #0x817FFFFF
ori r5, r5, 0xFFFF
addis r6, r4, 0x1000 #0x90000000
addis r7, r5, 0x1280 #0x93FFFFFF

cmplw r3, r4
cmplw cr5, r3, r5
cmplw cr6, r3, r6
cmplw cr7, r3, r7
cror 4*cr0+eq, 4*cr0+lt, 4*cr7+gt #Check if less than 0x80000000 ***or*** greater than 0x93FFFFFF; place result in cr0
crand 4*cr5+eq, 4*cr5+gt, 4*cr6+lt #Now check if its in between 0x817FFFC0 ***and*** 0x90000000; place result in cr5
cror 4*cr0+eq, 4*cr0+eq, 4*cr5+eq #If *any* of the two above conditions (cr0 and cr5) were true, branch to LR
beqlr-

And that's pretty much it. Happy coding!