Simple ASM Reference Page
#1
Have trouble writing ASM after reading my guide on How to Make Cheat Codes on Dolphin? Fear not, here are some commonly used ASM functions with examples provided.

ASM Examples

Using Hexadecimal vs Decimal Values

Hex values = 0x0000 (example - 0x0CAF)
Decimal = 0 (example - 9)

If using values for halfwords and words, it's better/easier to use Hex instead of decimal. It is also better/easier to use Hex for offset values.



Load Immediate

li r2, 10
Load the value 10 into Register 2. Register 2 is now 0x0000000A.

li r2, 0x00CC

Load the value 0x00CC into Register 2. Register 2 is now 0x000000CC



Add

add r6, r5, r4

r5 = 4
r4 = 5

Value of Registers 5 and 4 are added and result is stored in Register 6.

Register 6 now equals 0x00000009



Add Immediate

addi r6, r5, 2

r5 = 4

Value of Register 5 and 2 are added and result is stored in Register 6

Register 6 now equals 0x00000006

addi r3, 0, 1 is the same as li r3, 1

Special Note about Addi and r0: If r0 is placed in the middle of the function (ex: addi r7, r0, 5), it is treated by the compiler as simply 0.



Add Immediate Shifted

addis r6, r5, 2

r5 = 4

Value of 2 is added to upper 16 bits of Register 5. Since upper 16 bits of Register 5 was 0x0000. This would be 0 + 2, so upper 16 bits of Register 6 is 0x0002. Lower 16 bits of Register 5 are not effected and simply 'carried over' for result in Register 6.

Register 6 now equals 0x00020004

Special Note about Addis and r0: If r0 is placed in the middle of the function (ex: addis r9, r0, 0xD), it is treated by the compiler as simply 0.



Load Immediate Shifted

lis r1, 1

Load the value of 1 into the upper/first 16 bits of Register 1. Register 1's lower/second 16 bits are cleared (set to 0000)

Register 1 was 0x1500FFFF BEFORE the ASM
Register 1 is now 0x00010000

lis r1, 1 is the same as addis r1, 0, 1



Or Immediate

If you want to set a value on both the upper and lower 16 bits of a Register immediately, you need to implement the ori function:

lis r0, 1
ori r0, r0, 2

Register 0 is now 0x00010002



Store Word

stw r3, 0x0002 (r4)

r3 = 0x00000005
r4 = 0x80001574

Store the word of Register 3, into the address of Register 4 plus 0x0002

Address 0x80001576 now contains 0x00000005

Special note about stw and r0: If r0 is used as the source register (the register within the parenthesis) it is treated by the compiler as a value of 0x00000000.



Store Halfword

sth r3, 0x0002 (r4)

r3 = 0x00000005
r4 - 0x80001574

Store the half-word of Register 3 into the address of Register 4 plus 0x0002

Address 0x80001576 was 0x10002000 BEFORE THE ASM
Address 0x80001576 is now 0x00052000

Special note about sth and r0: If r0 is used as the source register (the register within the parenthesis) it is treated by the compiler as a value of 0x00000000.



Store Byte

stb r3, 0x0002 (r4)

r3 = 0x00000005
r4 = 0x80001574

Store the byte of Register 3 into the address of Register 4 plus 0x0002

Address 0x80001576 was 0x10002000 BEFORE THE ASM
Address 0x80001576 is now 0x05002000

Special note about stb and r0: If r0 is used as the source register (the register within the parenthesis) it is treated by the compiler as a value of 0x00000000.



Store Word Indexed

stwx r1, r2, r3

Store the value of Register 1 to the address of Register 3 with the added value of Register 2. When comparing stwx to stw, a use of a register is replacing the typical use of an offset value.

Register 1 = 0x12345678
Register 2 = 0x00000005
Register 3 = 0x80001000

Using the register values above, the word 0x12345678 is now stored to the address 0x80001005.

sthx is for halfwords, stbx is for bytes

Special note about stwx, sthx, and stbx when used with r0: If r0 is used as the 2nd source register (register on the far right) it is treated by the compiler as a value of 0x00000000.



Load Word & Zero

lwz r3, 0x0002 (r4)

Load the word at address of Register 4 plus 0x0002 into Register 3

Register 4 = 0x80001574
Word at Address 0x80001576 is 0x1500FFFF

Register 3 is now 0x1500FFFF

Special note about lwz and r0: If r0 is used as the source register (the register within the parenthesis) it is treated by the compiler as a value of 0x00000000.



Load Halfword & Zero

lhz r3, 0x0002 (r4)

Load the half-word at address of Register 4 plus 0x0002 into Register 3

Register 4 = 0x80001574
Word at Address 0x80001576 is 0x1500FFFF

Register 3 is now 0x00001500

Special note about lhz and r0: If r0 is used as the source register (the register within the parenthesis) it is treated by the compiler as a value of 0x00000000.



Load Byte & Zero

lbz r3, 0x0002 (r4)

Load the byte at address of Register 4 plus 0x0002 into Register 3

Register 4 = 0x80001574
Word at Address 0x80001576 is 0x1500FFFF

Register 3 is now 0x00000015

Special note about lbz and r0: If r0 is used as the source register (the register within the parenthesis) it is treated by the compiler as a value of 0x00000000.



Load Word & Zero Indexed

lwzx r1, r2, r3

The word at the address of Register 3 with the added value from Register 2 is loaded into Register 1. When comparing lwzx to lwz, the use of a register is replacing the typical use of an offset value.

Register 2 = 0x00000008
Register 3 = 0x80001000

The word at the address of 0x80001008 would be loaded in Register 1.

lhzx is for halfwords, lbzx is for bytes

Special note about lwzx, lhzx, and lbzx when used  with r0: If r0 is used as the 2nd source register (register on the far right) it is treated by the compiler as a value of 0x00000000.



Move Register

mr r4, r3

Value of register 3 is copied to register 4. This is the same thing as "copy-pasting", therefore the value in r4 is NOT removed.



Nop

Nop means no-operation. Basically its an ASM function done that will not effect any registers, values, addresses, etc. All source code (written ASM) must be an odd amount of ASM instructions, so Nops are needed as the last ASM function of any source code that is an even amount of instructions. 

Example:
li r0, 1
stw r0, 0 (r1)
nop

The nop is added to make the source code have an odd amount of ASM instructions

nop is the same as ori r0, r0, 0


Subtract Immediate

subi r5, r6, 2

The result of r6 minus the value of 2 will be stored in r5.

If...
r6 = 4
Then r5 would equal 2.

subi r5, r6, 2 is the same ass addi r5, r6, -2



Subtract

sub r12, r4, r31

If..
r4 = 0x0015
r31 = 0x0001
Then r12 would equal 0x0014

The value in Register 31 is subtracted FROM the value of Register 4. Result is stored in Register 12.



Subtract From

subf r9, r4, r5

If...
r4  = 0x0018
r5 = 0x00DD
Then r9 would equal 0x00C5

The value in Register 4 is subtracted FROM the value of Register 5. Result is stored in Register 9.



Multiply Low Word

mullw r2, r1, r0

Contents of r1 and r0 are multiplied together. If final number is a 64 bit value, the lower 32 bits of that value is stored in r2. If final number is a 32 bit value, the whole value in stored in r2.

If...
r0 = 0x00000005
r1 = 0x0000000B

Then r2 would equal 0x00000037



Multiply Immediate

mulli r2, r1, 0x0004

Value of r1 is multiplied with the value of 0x0004. Result is stored in r2.

If..
r1 = 0x0000000C

Then r2 would equal 0x00000030



Divide Word

divw r4, r30, r15

Value of r30 is divided by the value of r15. Result stored in r4.

If...
r30 = 0x00002000
and r15 = 0x000000004

Then r4 would equal = 0x00000500.

If rounding is needed, the number will round down to the closest whole number. Let's say your result from a divw instruction is going to be 1.9 (0x1.E66--- in hex), the actual result stored will be 1.



Compare Word

cmpw r0, r1

The value in r0 is compared to the value in r1. A 'if type' branch function will be after the cmpw. Values in r0 and r1 are signed.



Compare Word Immediate

cmpwi r0, 2

The value in r0 is compared to the value of 2. A 'if type' branch function will be after the cmpwi. Value in r0 and 2 are signed.



Branch

b some_label

li r5, 9

some_label:
lis r0, 0x0001
ori, r0, r0, 0x0001
stw r0, 0 (r1)

The code handler will branch (jump aka 'preform') the contents of some label. This causes the 'li r5, 9' to be skipped. Please note that this is not a 'if type' branch function that would come after a cmpwi.



Branch If Equal

cmpwi r5, 3
beq some_label:

li r5, 9

some_label:
stw r0, 0 (r1)
add r4, r3, r2

If the value of 3 EQUALS the contents of Register 5, then the some_label is executed, and the 'li r5 9' is NOT preformed.



Branch If Not Equal

cmpwi r5, 3
bne some_label:

li r5, 9

some_label:
stw r0, 0 (r1)
add r4, r3, r2

If the value of 3 does NOT equal the contents of Register 5, then some_label is executed, and the 'li r5, 9' is NOT preformed.

Other Branch 'if-type' ASM functions:
bgt = Branch If Greater Than
blt = Branch If Less Than
ble = Branch If Less Than Or Equal
bge = Branch If Greater Than Or Equal

Branch Hints:
To help the CPU preform better and not waste memory, you can add hints to the branches. This will reduce prediction time by the CPU to determine if it should follow the branch or not.
+ = Branch most likely to be taken
- = Branch most likely to NOT be taken

Example using Branch Hints:
cmpwi r0, 0xA
bne+ some_label

This tells the CPU that it is most likely the value of A is not equal to value in r0.
---

cmpwi r0, 0xA
bne- some_label

This tells the CPU that it is unlikely the value of A is not equal to value in r0.



Shift Left Word Immediate

slwi r5, r31, 16

The word of Register 31 is shifted to the left by the amount of bits (16) provided by the integer on the far right. The result is stored in r5.

Example:
If r31 is 0x12345678 before the function...

Then r5 will be 0x56780000 after the function.

Each byte length of shift is equal to 8 bits. Usually, when this function is written in a code by a code creator, a shift of 8, 16, or 24 bits are the only values used.



Shift Word Right Immediate

srwi r14, r14, 8

The word of Register 14 is shifted to the right by the amount of bits (8) provided by the integer on the far right. The result is stored back into r14.

Example:
If r14 is 0x00A010FF before the function...

Then r14 will be 0x0000A010 after the function.

Each byte length of shift is equal to 8 bits. Usually, when this function is written in a code by a code creator, a shift of 8, 16, or 24 bits are the only values used.



Move to Count Register

mtctr r11

The value in r11 will be copied to the Count Register (CTR), whatever value that was in the CTR beforehand is wiped.



Move from the Count Register

mfctr r11

The value in the Count Register (CTR) is copied to r11, whatever value that was in r11 beforehand is wiped.



Branch Decrement When Not Zero

bdnz some_label

The branch to some_label will be taken if and only if the count register does NOT have the value of 0.

some_label
stw r4, 0x0 (r5)
addi r4, 0x4
bdnz some_label
li r12, 0x0

The count register will decrease by 1 every time the bdnz function is executed. Any time the count register is NOT zero, the branch to some_label will be taken. Once the countdown register is 0 after the bdnz is executed, the li r12, 0x0 function will now execute, and code will continue normally.

Branch Hints for bdnz:
bdnz+ Branch will most likely occur 
bdnz- Branch will most likely not occur



Move From Link Register

mflr r0

The value in the Link Register is moved (copied) to Register 0.



Move To Link Register

mtlr r0

The value in Register 0 is moved (copied) to the Link Register



Branch & Link

li r29, 0x0
b another_label

some_label:
lhz r31, 0x00EC (r12)
sth r31, 0x0 (r5)
blr

another_label:
li r5, 0xD
mr r30, r5

bl some_label

stw r30, 0x017D (r3)

Branch & Links are used to create subroutines. In this example, the first ASM function shown is jumping to 'another_label'. Then the 'another_label' ASM functions are executed. Afterwards, a branch will be taken to some_label. However it also stores the current location/address into the Link Register. 

Once the ASM functions for 'some_label' are executed, you will see there is a 'blr' function. Almost all the time, blr's are included at the end of a subroutine from a Branch & Link. This will allow you to jump back to your original routine. Once the blr is executed, you will be brought back to the next step after 'bl some_label', which is the 'stw r30, 0x017D (r3).

Some Variations of Branch & Link:
beql = Branch & Link If Equal
bnel = Branch & Link If Not Equal
bgtl = Branch & Link if Greater Than
bltl = Branch & Link if Less Than

You can also add branch hints to these variations (ex: bnel+). However, you cannot add a hint to a plain jane 'bl' as a 'bl' is an unconditional jump.



Branch to Link Register

stw r5, -0x0002 (r31)
blr

This example will execute the stw function then branch to the address that is currently held in Link Register. To understand how to use this branch more, read the example + explanation for the 'Branch & Link' ASm function.

Some Variations of Branching to the Link Register:
beqlr = Branch to Link Register if Equal
bnelr = Branch to Link Register if Not Equal
bgtlr = Branch to Link Register if Greater Than
bltlr = Branch to Link Register if Less Than

You can also add branch hints to these variations (ex: bnelr+). However, you cannot add a hint to a plain jane 'blr' as a 'blr' is an unconditional jump.



Store Multiple Words

stmw r29, 0x00EC (r5)

The words from r29 to r31 are all stored starting at address of r5 plus offset of 0xEC. The source register (r5 in the example) must never be a higher register than the destination register (r29 in example). Also, the value of r5 plus 0x00EC must be a multiple of 0x4 (end in 0x0, 0x4, 0x8, or 0xC).

So let's say r29 is 0x00001000, r30 is 0x00002000, and r31 is 0x00003000. Address of r5 plus 0xEC will have the word of 0x00001000, at offset 0xF0 will be the word of 0x00002000, and at offset 0xF4 will be the word of 0x00003000.



Load Multiple Words

lmw r29, 0x00EC (r5)

The values in r29 thru r31 will be replaced by the words starting at address of r5 plus offset 0xEC. The source register (r5 in the example) must never be a higher register than the destination register (r29 in example). Also, the value of r5 plus 0x00EC must be a multiple of 0x4 (end in 0x0, 0x4, 0x8, or 0xC).

Let's say starting at address r5 offset EC, we have these 3 words: 
0x0000A0000
0x0000B0000
0x0000C0000

After the function is executed, r29 will be 0x0000A0000, r30 will now be 0x0000B0000, and r31 will now be 0x0000C0000.



Store String Word Immediate

stswi r3, r25, 12

The first 12 consecutive bytes starting from register 3 going towards higher register values are stored to the address of Register 25

If..
r3 = 0x10203040 <--First 4 out of 12 bytes
r4 = 0xFFFF0000 <--Second 4 out of 12 bytes
r5 = 0x000000028 <--Third 4 out of 12 bytes
r25 = 0x8167DE00

Then...
The entire value of 0x10203040FFFF000000000028 is stored at address 0x8167DE00. Most codes will use values (for the byte amount) that are divisible by 4. However, you can do something such as 10 bytes which causes only the first 2 bytes of the 3rd register to be included in the storing instruction.



Load String Word Immediate

lswi r3, r25, 12

The 12 bytes of data starting at the address in r25 will be loaded into the first 12 consecutive bytes starting at register 3 going towards the higher registers

If..
r25 = 0x8167DE00

And the 12 bytes starting at that address is 0x10203040FFFF000000000028

Then after the instruction is executed..
r3 = 0x10203040
r4 = 0xFFFF0000
r5 = 0x00000028

Most codes will use values (for the byte amount) that are divisible by 4. However, you can do something such as 10 bytes which causes only the first 2 bytes of the 3rd register to be replaced during the loading instruction.



Store Word & Update

stwu r25, r31, 0x0008

Store the value in r25 to the address of r31 plus 0x0008. Afterwards the address in r31 is incremented by 0x0008.

Example:
If....
r25 = 0x1000270F
r31 = 0x80001600

When the stwu function is first executed, the value of 0x1000270F is stored at the address of 0x80001608. Register 31 is then updated to have the value of 0x80001608. Therefore, if this function is executed again, the 0x1000270F will be stored again to the address of 0x8000160C. The 'updating' of Register 31 will occur every time the function is executed.

sthu is for halfwords, stbu is for bytes



Load Word & Zero Then Update

lwzu r27, r4, 0x1000

Load the word at address of Register 4 plus 0x1000 into Register 27. Afterwards the address of Register 4 is incremented by 0x1000

Example:
If...
r4 = 0x80EF0050

When the lwzu function is first executed, the word at address is 0x80EF1050 is loaded into Register 27. Register 4 is then updated to have the value of 0x80EF1050. Therefore, if this function is executed again, the word at address 0x80EF2050 will now be loaded into Register 27. The 'updating' of Register 4 will occur every time the function is excuted.

lhzu is for halfwords, lbzu is for bytes



Add Immediate Carrying

addic r2, r2, 1

The value of 1 is added to the value in r2. The result is stored in r2. The carry bit in the Fix Point Exception Register will reflect the result of the operation. This means that if the result of the addition exceeds the capacity of the register, the carry bit (aka flag) in the Fix Point Exception Register (XER) will be set to 1.



Subtract Immediate Carrying

subic r18, 15, 1

The value of 1 is used as the amount of subtract from the value in r15. Result is stored in r18. The carry bit in the Fix Point Exception Register will reflect the result of the operation.

subic r18, r15, 1 is the same as addic r18, r15, -1



Subtract Immediate Carrying & Record

subic. r17, r17, 1

The value of 1 is first used as the amount to subtract from the value in r17. Second, the result is stored back into r17. Then, the Record (.) aka Dot function is a shortcut for cmpwi r17, 0x0. Therefore you can then list something such as a beq as the very next function below the subic. function. Finally, the carry bit in the Fix Point Exception Register will reflect the result of the operation.



Compare Logical Word Immediate


This instruction compares a value of a register to an integer. The values for the comparison are unsigned (no negative reading of values allowed). 

cmplwi r4, 0x11
bgt- some_label

Let's say r4 = 0xFFFFFFE7. On a standard cmpwi r4, 0x11 instruction, the some_label route will NOT be taken as cmpwi treats 0xFFFFFFE7 as a negative value (-0x19) since it is signed. With cmpwli instruction, the value 0xFFFFFFE7 is unsigned and it is thus a positive number causing some_label branch to be taken



Compare Logical Word

This instruction compares a a value in register to a value in a another register. The values for the comparison are unsigned. (no negative reading of values allowed)

cmplw r4, r5
bgt- some_label

Let's say r4 = 0xFFFFFF9B and r5 = 0x00000008. On a standard cmpw r4, r5 instruction, the some_label route will NOT be taken as cmpw treats 0xFFFFFF9B as a negative value (-0x65) since it is signed. With cmplw instruction, r4's value is unsigned and it is thus a positive number causing some_label branch to be taken.




Store Floating Single

stfs f3, 0x0C10 (r31)

The single precision floating point value in floating point register 3 will be stored to address of Register 31 plus offset 0x0C10.

Let's say value in f3 is 0x41E00000 00000000...

The word 0x41E00000 will be stored to address of r31 plus offset 0x0C10



Store Floating Double

stfd f0, 0x0020 (r4)

The double precision floating point value in floating point register 0 will be stored to address of Register 4 plus offset 0x0020.

Let's say value in f0 is 0x3FF00000 20000000...

The entire value in f0 will be stored as a double word to address of r4 plus offset 0x0020



Load Floating Single

lfs f1, 0 (r29)

The float-single (word) at address of r29 will be loaded into floating point register 1.

Let's say r29 = 0x901A3C44
And... value at r29 is 0x3F800000

f1 will then equal 0x3F800000 00000000



Load Floating Double

lfd f0, 0x8 (r3)

The float-double (double word) at address of r3 plus offset 0x8 will be loaded into floating point register 0.

Let's say r3 = 0x80387000
And... value at r3 plus 08 offset is 0x43300000 00000008

f0 will then equal 0x43300000 00000008



Floating Convert To Integer

fctiw f2, f6

The double precision floating point value in floating point register 2 will be converted to an integer. If the integer has to be rounded, it will be rounded to its closest whole number. The result will be stored in f6.

If f2 = 0x40583000 00000000...

This value in integer form is 96.75 in decimal. Therefore, the instruction will covert the value to the rounded integer decimal amount 97 (0x61).

f6 will contain the result - 0xFFF80000 00000061.



Floating Convert To Integer Then Round Towards Zero

fctiwz f0, f0

The double precision floating point value in floating point register 0 will be converted to an integer. If the integer has to be rounded, it will round its lower whole number. The result is stored back into f0.

If f0 = 0x40583000 00000000..

This value in integer form is 96.75 decimal. Therefore, the instruction will convert the value to the rounded integer decimal amount 96 (0x60).

f0 will contain the result - 0xFFF80000 00000060.



Store Floating Point As Integer Word Indexed

stfiwx f5, r11, r27

The lower 32 bits of the value in floating point register 5 will be stored to the address of r27 and use the value in r11 as the offset amount. A code creator will use this instruction once a float has already been converted to an integer. This instruction saves the Code Creator from extra work. If a Code Creator doesn't utilize this instruction, then he/she will have to store the float (using stfd) to a temporary spot in RAM and then reload it (using lfd) later on. Please note that this instruction does not actually convert float values to integers!

If...
f5 = 0xFFF80000 00000071
r11 = 0x00000008
r27 = 0x8EF1111C

Then the word 0x00000071 will be stored to address 0x8EF11124.
Reply
#2
Great simplification! This guide will definitely be helpful when I start working on ASM.
Reply
#3
I hope you guys don't mind, but here's some stuff I found about Assembler Application Note:
http://wiibrew.org/wiki/Assembler_Tutorial

don't worry, i'm not trying to flood with posts, just figured this'd help more advanced users understand PowerPC processors and intel assemblers and all.

personally, i'm gonna hold off on this kind of stuff until I do some 04 codes and all that good stuff

peace
Reply
#4
(10-30-2018, 04:08 AM)xXCrazySniperXx Wrote: I hope you guys don't mind, but here's some stuff I found about Assembler Application Note:
http://wiibrew.org/wiki/Assembler_Tutorial

don't worry, i'm not trying to flood with posts, just figured this'd help more advanced users understand PowerPC processors and intel assemblers and all.

personally, i'm gonna hold off on this kind of stuff until I do some 04 codes and all that good stuff

peace

That link is already supplied in the Dolphin tut...... This page is meant to be a reference page, not a tut page
Reply
#5
Oops... I read your message long after i posted this stuff, sorry about that.
Reply
#6
No worries
Reply
#7
Isn't ASM also used in the GameCube? Just wondering... I figured ASM could be used to hack both Wii and GC since they both run on the same processor family. One day, MKGC could get hacked too, although it'd be about 12 years too late lol.
Reply
#8
Yes ASM is used in Gamecube. I have no experience whatsoever with anything Gamecube related unfortunately. So I wouldn't be much help if any.
Reply
#9
Bump, several revisions made
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)