Mario Kart Wii Gecko Codes, Cheats, & Hacks
Logical Operations for PPC ASM - Printable Version

+- Mario Kart Wii Gecko Codes, Cheats, & Hacks (https://mariokartwii.com)
+-- Forum: Guides/Tutorials/How-To's (https://mariokartwii.com/forumdisplay.php?fid=45)
+--- Forum: PowerPC Assembly (https://mariokartwii.com/forumdisplay.php?fid=50)
+--- Thread: Logical Operations for PPC ASM (/showthread.php?tid=1824)



Logical Operations for PPC ASM - Vega - 04-23-2021

Logical Operations for PPC ASM

For ASM Coders who already know the basics.



Chapter 1: Fundamentals

This thread will teach you how to do various logical operations in PowerPC Assembly. Values you see in registers are obviously displayed in Hex. These Hex values are actually 'compiled' forms of binary. Binary is difficult to read so this is why values in registers are in Hex form. A Binary value is known as a bit. Bits can only be 0's or 1's.

For example, let's say r5 has a value 0x12300BCD. Each GPR is 32 bits in length. Since there are 8 digits of Hex in a GPR, that means each Hex digit represents 4 bits of binary. The value in r5 in Binary is this....

0001 0010 0011 0000 0000 1011 1100 1101

The range of a Hex digit is 0x0 thru 0xF and this can be displayed in binary when the binary representation is split into groups of 4. So this grouping of 4-bits gives you an easy visual representation of the register's value in binary. The first bit (also called the sign bit or the most significant bit) is bit 0. The last bit (also called least significant bit) is bit 31.

When a bit is '1', that means the bit is High/True. When a bit is '0',that means the bit is Low/False.

Here is a list of all binary to hex digit conversions:
Code:
0000 = 0x0
0001 = 0x1
0010 = 0x2
0011 = 0x3
0100 = 0x4
0101 = 0x5
0110 = 0x6
0111 = 0x7
1000 = 0x8
1001 = 0x9
1010 = 0xA
1011 = 0xB
1100 = 0xC
1101 = 0xD
1110 = 0xE
1111 = 0xF

Btw, here's a good online converter (you can swap back & forth) - https://www.rapidtables.com/convert/number/hex-to-binary.html

Logical Operations on done on a per bit basis. Let's say we have a value in r3 and we preform a logical operation with the value in r27. Bit 0 of r3 will have a logical operation done in reference to bit 0 of r27. Bit 1 of r3 will have an operation done in reference to bit 1 of r27, and so on and so on.

Needless to say that all logical instructions of Broadway treat their values logically (unsigned).



Chapter 2: Logical OR

Logical ORing is one of the most commonly used logical operations. ORing means if at least value#1 or value#2 is true, then the result is true.

Binary Diagram:

Code:
Bit Value rA  Bit Value rB Bit Result rD
0                0            0
0                1            1
1                0            1
1                1            1

Scaling up from binary to a hex word value, if r3 has a value of 0x00000001, and r27 has a value of 0x80000001, and these two values are OR'd together, it would produce a result of 0x80000001. Confused by this? let's break it down in binary view...

r3  - 0000 0000 0000 0000 0000 0000 0000 0001
r27 - 1000 0000 0000 0000 0000 0000 0000 0001

Using the binary diagram provided above, and you preform a logical OR for every bit, then the result in binary is...

1000 0000 0000 0000 0000 0000 0000 0001

Convert that to Hex and you get 0x80000001.

Broadway comes with the following Logical OR instructions:

Code:
or rD, rA, rB #rA is OR'd with rB, result placed in rD. This instruction comes with the ability to use the Record feature (free use of cmpwi rD, 0).

ori rD, rA, VALUE #rA is OR'd with 0x0000VVVV with VVVV being VALUE, the result is placed in rD.

oris rD, rA, VALUE #rA is OR'd with 0xVVVV0000 with VVVV being VALUE, the result is placed in rD.

Referring back from the beginner's Assembly Tutorial HERE, you should now have an understanding of why the usage of the lis and ori instructions are preformed to write entire 32-bit (word) values from scratch to a GPR.

You may find yourself in a scenario where you need set a bit high and not mess with the other bits in a register. Here's an example where we need load a value into a register, set its bit value high, then store the value back.

Code:
lwz rX, 0xZZZZ (rY)
oris rX, rX, 0x8000
stw rX, 0xZZZZ (rY)

Fyi: nop is a simplified mnemonic of ori r0, r0, 0x0000
Fyi: mr rD, rA is a simplified mnemonic of or rD, rA, rA #rA is logically OR'd with itself



Chapter 3: Logical AND

Another commonly used logical operation is AND. AND means if both inputs are true, then the result is true, otherwise the result is always false. Here is a binary diagram for AND~

Code:
Bit Value rA  Bit Value rB Bit Result rD
0                0            0
0                1            0
1                0            0
1                1            1

ANDing operations for Broadway:

Code:
and rD, rA, rB #rA is AND'd with rB; result in rD. Comes with a Record feature if needed.

andi. rD, rA, VALUE #rA is AND'd with 0x0000VVVV with VVVV being VALUE, the result is placed in rD. A form of this instruction withOUT the Record feature does NOT exist. The upper 16 bits of rD will always result in 0x0000!

andis. rD, rA, VALUE #rA is AND'd with 0xVVVV0000 with VVVV being VALUE, the result is placed in rD. A form of this instruction withOUT the Record feature does NOT exist. The lower 16 bits of rD will always result in 0x0000!

ANDing can be a good way to check if certain bits are high. Let's say a r19 has a value and you want to check if bit 30 is high. If not, take the branch

Code:
andi. r0, r19, 0x0002 #Temporarily use r0 to place result in.
bne- some_label

If you were wanting to check if multiple bits are all high, you will need to add in a comparison instruction. Let's redo the same example as earlier but now check if BOTH bots 30 and 31 are high. If not, take branch.

Code:
andi. r0, r19, 0x0003
cmpwi r0, 0x0003
bne- some_label

If you only cared if either one was high, then you don't need the 'cmpwi r0, 0x0003' instruction.



Chapter 4: Logical XOR

XOR aka Exclusive OR is a logical operation that is also pretty common. Logical XOR's only produce a true result when the inputs are opposite values. If both inputs are the same bit value, then the result is always false.

Code:
Bit Value rA  Bit Value rB Bit Result rD
0                0            0
0                1            1
1                0            1
1                1            0

XORing operations for Broadway:

Code:
xor rD, rA, rB #rA is XOR'd with rB; result in rD. Comes with a Record feature if needed.

xori rD, rA, VALUE #rA is XOR'd with 0x0000VVVV with VVVV being VALUE, the result is placed in rD.

xoris rD, rA, VALUE #rA is XOR'd with 0xVVVV0000 with VVVV being VALUE, the result is placed in rD.

A handy trick with XOR is that it can be used to flip a bit value regardless of what the current bit value is. Let's say you are working on a code where r31 is either 0 or 1. For whatever reason, you need this value to flipped (0 to 1; 1 to 0) in your code. A beginner ASM Coder who isn't familiar with XORing might write a source like this..

Code:
#Check r31
cmpwi r31, 0

#Preset r31 to 1 before branch
li r31, 1

#Do branch. If branch is taken, r31 was originally 0 and is now 1, we're done
beq- done

#r31's original value was 1, make it 0
li r31, 0

#Done
done:

That source is frankly silly. Since r31's value (0 or 1) is determined by bit 31 alone, you can simply XOR bit 31 with the value of 1 to flip r31's value.

Code:
xori r31, r31, 0x0001 #Flip slot value. 0 = 1, 1 = 0. Place result in back in r31.

Another trick for XOR'ing is using it as a glorified bit 'subtraction' (removal) mechanism. Check out the source of this code (has logical AND, XOR, & OR) - https://mariokartwii.com/showthread.php?tid=48

What the source is doing is..
1. Checking if a button (key #1; XXXX value) was at least hit (notice the logical AND usage)
2. If so, flip that button's bit low (notice the XOR usage)
3. Make key #2 (YYYY value) button bit high (notice the OR usage)
4. End code with original/default instruction

In conclusion if you need to 'flip' a bit, logical XORing is what you need.



Chapter 5: Other Logical Operations

Broadway also comes with...
  • nor (includes Record feature)
  • nand (includes Record feature)
  • eqv #also known as xnor but you must use the operand eqv in the compiler (includes Record feature)

Logical NOR is the exact opposite of OR. So if any ORing result would be 0, then NOR's result would be 1 and vice versa.

Binary Diagram of NOR

Code:
Bit Value rA  Bit Value rB Bit Result rD
0                0            1
0                1            0
1                0            0
1                1            0

If you logically NOR a value with itself, you will actually just flip every bit to it's opposite value. This is known as a logical NOT. You can use the simplified mnemonic 'not' to preform this type of operation.

Code:
not rD, rA #same this as nor rD, rA, rA

Logical NAND is the opposite of AND.

Binary Diagram of NAND

Code:
Bit Value rA  Bit Value rB Bit Result rD
0                0            1
0                1            1
1                0            1
1                1            0

Binary Diagram of EQV aka XNOR (Exclusive NOR); it's the opposite of XOR.

Code:
Bit Value rA  Bit Value rB Bit Result rD
0                0            1
0                1            0
1                0            0
1                1            1



Chapter 6: Conclusion

Here's a good logical operations calculator - https://keisan.casio.com/exec/system/14495408631029

Understanding logical operation instructions is a must if you are working on a code that has a value in a register that uses bits to represent something such as a characters, levels, maps, items, etc. Happy coding!