Mario Kart Wii Gecko Codes, Cheats, & Hacks
More Info about Comparisons and Branches - Printable Version

+- Mario Kart Wii Gecko Codes, Cheats, & Hacks (https://mkwii.com)
+-- Forum: Guides/Tutorials/How-To's (https://mkwii.com/forumdisplay.php?fid=45)
+--- Forum: Power PC Assembly (https://mkwii.com/forumdisplay.php?fid=50)
+--- Thread: More Info about Comparisons and Branches (/showthread.php?tid=1743)



More Info about Comparisons and Branches - Vega - 01-30-2021

More Info about Comparisons and Branches

I was getting some messages recently from new ASM learners who were still confused about logical and signed values when it comes to comparison + branches. This thread will also dive into great detail about the condition register, CR fields, and what comparison instructions actually do.

First understand that cmpw and cmpwi are used for signed value comparisons. While cmplw and cmplwi are for logical/unsigned value comparisons. Refer back to the Assembly Tutorial HERE if needed.

Signed 16 bit range for cmpwi: 0xFFFF8000 thru 0x7FFF (-32768 thru 32767)
Logical 16 bit range for cmpwi: 0x0000 thru 0xFFFF (0 thru 65535)

Examples~

Code:
cmpwi r3, 0x1388 #This is valid
cmpwi r3, 0x24C00 #This is NOT valid

Code:
cmplwi r3, 40000 #This is valid
cmplwi r3, -1 #This is NOT valid

If you need to work with numbers outside of these ranges (or work with values exceeding 16 bits), you must set the value in a register then do a register vs register (cmpw/cmplw) comparison.

Examples~

Code:
#Do a signed comparison or r3 against the value of 0x80000000 (placed in r5)
lis r5, 0x8000
cmpw r3, r5

Code:
#Do a logical comparison of r3 against the value of 0x8055EF68 (placed in r5)
lis r5, 0x8055
ori r5, r5, 0xEF68
cmplw r3, r5



Now that you understand the range of signed and logical values in using comparison instructions, its a good thing to know that if your branch instruction that's after your comparison is a beq (branch if equal) or bne (branch if not equal), then your comparison can be logical or signed, it doesn't matter as long as you still follow the rules for the number ranges. This is because you are only checking if values are a match, whether or not said values are logical or signed doesn't effect this match.

Example~

Code:
lis r5, 0x8000
cmpw r3, r5
bne- some_label

will execute the exact same as...

Code:
lis r5, 0x8000
cmplw r3, r5
bne- some_label

and...

Code:
lis r5, 0x8055
ori r5, r5, 0xEF68
cmplw r3, r5
beq- some_label

will execute the exact same as...

Code:
lis r5, 0x8055
ori r5, r5, 0xEF68
cmpw r3, r5
beq- some_label



When it comes to any branch instructions that involve a 'greater/lesser' (bgt, bge, blt, and ble), you need to be sure your comparison is the correct type (signed vs logical) or else your branch might execute differently than what you are expecting.

Let's say your code loads a word value from memory into r3, and you want to check said value against what you have in r4. If r3 is less than r4, we want a branch to be taken. Look at the following sources below. Also, let's pretend r3 ended up with a value of -10 while r4 has a value of 10.

Code:
lwz r3, 0 (r5) #r5 is an address in memory where our r3 value is located; load value into r3
cmpw r3, r4 #Compare r3 (-10) to r4 (10)
blt- some_label

^The above source is correct. Since r3 vs r4 was a signed comparison, r3 was treated as a negative value (-10) and is thus less than r4 (10), so the branch will be taken. Let's observe an incorrect source..

Code:
lwz r3, 0 (r5)
cmplw r3, r4
blt- some_label

^This would be incorrect, The comparison was done logically which will treat r3 as a positive value. Remember your decimal to hex conversion. r3 is -10 which in hex the register value will be 0xFFFFFFF6. The hex value in r4 (10) is 0x0000000A. 0xFFFFFFF6 is greater than 0x0000000A (when numbers are treated logically), so this will cause the branch to NOT be taken, which is not what we wanted.



What Comparison Instructions actually do:

NOTE: This section may be a bit overwhelming for the beginner ASM coder, you don't really need to understand this unless you are making some complex codes.

When a comparison is executed, the processor will edit the Condition Register (CR) accordingly based on the result said comparison. The following branch instruction reads the Condition Register and if certain values are present/not-present, the branch will be taken.

Before diving deeper into the Condition Register, lets breakdown a typical signed comparison instruction against the value of 1.

Code:
cmpwi r3, 1 = cmpi cr0, 0, r3, 1

The comparison instructions you see in Wii cheat codes are actually simplified mnemonics.

cmpi = do a signed integer comparison (fyi: cmpli = logical integer comparison, cmp = signed register comparison, cmplw = logical register comparison)

cr0 = This is the CR field. There are 8 CR fields (cr0 thru cr7). Each field takes on one digit (or half of a byte) in the Condition Register.

Condition Register layout
STUVWXYZ

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

0 = L bit. For Broadway, this must always be 0 or else it is an invalid instruction and will cause an exception/freeze. For anyone who cares, a '1' for the L bit is for a 64 bit comparison while '0' is for a 32 bit comparison. In lamest terms, you could say this was 'left' in by the Broadway devs from previous work of other PPC assembly languages.

r3 and 1 is obviously comparing the value in r3 vs the signed 16 bit value value of 0x0001.

cr0 is the CR field used for basic integer comparisons, which account for (if i had to guess) around 95% of comparisons done in Wii cheat codes. cr1 is used for floating point comparisons. Sometimes a coder may need to use another CR field while not wanting to modify cr0 or cr1. This is easy to do, just specify the CR field like so..

Code:
cmpwi cr7, r3, 1

This will put the comparison result in cr7 instead of cr0. Now when you want to branch based on the result that's placed in cr7, do this...

Code:
bne+ cr7, some_label #bne+ just used as an example ofc, can be any branch instruction

Just add the CR field then a comma to specify its to prevent the assembler from defaulting to cr0.

NOTE: Never use cr2 thru cr4. If you need extra cr fields, start with cr7, then cr6, and then cr5. There's no way you will need more than 3 extra cr fields in a Wii code, lol.



More in-depth details of the Condition Register

NOTE: Once again, if you are a beginner and are overwhelmed, don't worry about reading the following contents.

There are certain bit values within each CR field, here is a list of them.

Code:
bit 0 = <0 flag
bit 1 = >0 flag
bit 2 = =0 flag
bit 3 = SO (Summary overflow)

Comparison instructions will flip the corresponding bit(s) high/low based on the result of the comparison. Any unrelated bits are left alone. And the branch instructions will check certain bits, and execute based on whether certain hits are flipped high and/or low.

List of branch instruction bit checks~

Code:
beq (branch if equal) = checks bit 2, if bit is high, branch is taken
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

NOTE: The branch instructions are all simplified mnemonics. In fact every branch instruction you see in a source of a Wii cheat code will be a simplified mnemonic. There's really no point breaking down the complexity of all these mnemonics as it doesn't help the Coder at all to try to use the actual 'real form' branch-conditional (bc) instructions.



Final section: Instructions allowing modification of the CR w/o using comparisons

Want CR's value in a register or vice versa?? There are instructions for that...

mfcr rD #Copy the value of CR to rD
mtcr rD #Copy the value of rD to the CR

Here's a handy instruction to copy the value of one CR field and paste it in another CR field...

mcrf crD, crA #Copy value of crA, paste it in crD

Example~

Code:
mcrf cr7, cr0 #This will copy the value of CR field 0 and paste it in CR field 7.


Here are a couple of handy instructions if you need to manully flip bit(s) high/low in a CR field

crset B #B = the bit of the CR register, see bit map below for assistance. This will flip the desired bit high.
crclr B #This will flip the desired bit low

Code:
bit map:
bits 0 thru 3 = cr0's bits
bits 4 thru 7 = cr1
bits 8 thru 11 = cr2
bits 12 thru 15 = cr3
bits 16 thru 19 = cr4
bits 20 thru 23 = cr5
bits 24 thru 27 = cr6
bits 28 thru 31 = cr7

crset B is a simplified mnemonic of creqv B, B, B
crclr B is a simplifed mnemonic of crxor B, B, B

For even more condition register instructions, refer back to your favorite PPC manual.