Simple ASM Reference Page
#1
Simple ASM Reference Page

Here are some commonly used ASM instructions with detailed examples provided. More commonly used instructions in MKWii ASM Codes will be listed first, while the more uncommon instructions will be listed last.

General overview:
Instruction Name
Syntax
Signed or Logical (if applicable)
Example
Notes + Description

Notes for Syntax format:
rD = Destination General Purpose Register
rA = Source General Purpose Register
rB = 2nd Source General Purpose Register
VALUE = 16 bit Immediate Value, (shifting, clearing, and string store/load instructions have different rules for VALUE)
fD = Destination Floating Point Register
fA = Source Floating Point Register

Note about r0:

For the following instructions...
addi
addis
subi
all store-type,non-float instructions that are not stwm or stswi
all load-type,non-float instructions that are not lwm or lswi

If r0 is used as the source register, it will be treated by the compiler as simply 0 .



Load Immediate

li rD, VALUE

Signed

li r2, 0x00CC

Load the value 0x00CC into Register 2.

Register 2 is now 0x000000CC



Add

add rD, rA, rB

Signed

add r6, r5, r4

Value of Register 5 and the value of Register 4 are added together. The result is stored in Register 6.

If..
r5 = 4
r4 = 5

Then Register 6 would equal 0x00000009



Add Immediate

addi rD, rA, VALUE

Signed

addi r6, r5, 2

Value of Register 5 and the value of 2 are added together. The result is stored in Register 6

If..
r5 = 4

Then Register 6 would equal 0x00000006



Add Immediate Shifted

addis rD, rA, VALUE

Signed

addis r6, r5, 2

Value of 2 is added to Upper 16 bits of Register 5. The result is stored in Register 6. 

If...
r5 = 4

Then Register 6 would equal 0x00020004. 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 remain unaffected.



Load Immediate Shifted

lis rD, VALUE

Signed

lis r1, 1

Load the value of 1 into the Upper 16 bits of Register 1. Register 1's Lower 16 bits are cleared automatically (set to 0000).

Register 1 is now 0x00010000



Or Immediate

ori rD, rA, VALUE

Logical

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 instruction:

lis r4, 0x8000
ori r4, r4, 0x15EC

Register 4 is now 0x800015EC



Store Word

stw rD, VALUE (rA)

Signed

stw r3, 0x0002 (r4)

Store the word of Register 3 to the address Register 4 plus 0x0002.

If...
r3 = 0x00000005
r4 = 0x80001574

Then the word at Address 0x80001576 would equal 0x00000005.



Store Halfword

sth rD, VALUE (rA)

Signed

sth r3, 0x0002 (r4)

Store the halfword of Register 3 to the address of Register 4 plus 0x0002.

Let's say...
r3 = 0x00000005
r4 - 0x80001574

If the word at Address 0x80001576 was 0x10002000 before the instruction was executed then...
the word Address 0x80001576 is 0x00052000 after the instruction has executed.



Store Byte

stb rD, VALUE (rA)

Signed

stb r3, 0x0002 (r4)

Store the byte of Register 3 to the address of Register 4 plus 0x0002.

Let's say...
r3 = 0x00000005
r4 = 0x80001574

If Address 0x80001576 was 0x10002000 before the instruction was executed then...
the word at Address 0x80001576 is 0x05002000 after the instruction has executed.



Store Word Indexed

stwx rD, rA, rB

Signed

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.

If...
r1 = 0x12345678
r2 = 0x00000005
r3 = 0x80001000

Then the word at Address 0x80001005 would equal 0x12345678.

sthx is for halfwords, stbx is for bytes



Load Word & Zero

lwz rD, VALUE (rA)

Signed

lwz r3, 0x0002 (r4)

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

If...
r4 = 0x80001574
Word at Address 0x80001576 = 0x1500FFFF

Then Register 3 would equal 0x1500FFFF.



Load Halfword & Zero

lhz rD, VALUE (rA)

Signed

lhz r3, 0x0002 (r4)

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

If...
r4 = 0x80001574
Word at Address 0x80001576 = 0x1500FFFF

Then Register 3 would equal 0x00001500.



Load Byte & Zero

lbz rD, VALUE (rA)

Signed

lbz r3, 0x0002 (r4)

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

If...
r4 = 0x80001574
Word at Address 0x80001576 = 0x1500FFFF

Then Register 3 would equal 0x00000015.



Load Word & Zero Indexed

lwzx rD, rA, rB

Signed

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.

If...
r2 = 0x00000008
r3 = 0x80001000
Word at Address 0x80001008 = 0x000000FF

Then Register 1 would equal 0x000000FF.

lhzx is for halfwords, lbzx is for bytes



Move Register

mr r4, r3

Logical

Value of register 3 is copied to register 4.



Nop

Logical

Nop means no-operation. Basically its an instruction done that will not effect any registers, values, addresses, etc. All source code must be an odd amount of instructions, so a Nop is needed as the last instruction of any source code that is an even amount of instructions. However, all PowerPC compilers will add this Nop automatically for you when you compile your source. 

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

nop is the same as ori r0, r0, 0



Subtract Immediate

subi rD, rA, VALUE

Signed

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.



Subtract

sub rD, rA, rB

Signed

sub r12, r4, r31

The result of r4 minus r31 will be stored in Register 12.

If..
r4 = 0x0015
r31 = 0x0001

Then r12 would equal 0x0014



Subtract From

subf rD, rA, rB

Signed

subf r9, r4, r5

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

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



Multiply Low Word

mullw rD, rA, rB

Signed

mullw r2, r1, r0

Contents of r1 and r0 are multiplied together. If final number is a 64 bit value, only 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 rD, rA, VALUE

Signed

mulli r2, r1, 0x0004

Value of r1 is multiplied with the value of 0x0004. Result is stored in r2. If final number is a 64 bit value, only 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..
r1 = 0x0000000C

Then r2 would equal 0x00000030



Divide Word

divw rD, rA, rB

Signed

divw r4, r30, r15

Value of r30 is divided by the value of r15. Result stored in r4. 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.

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

Then r4 would equal 0x00000800.



Compare Word

cmpw rD, rA

Signed

cmpw r0, r1

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



Compare Word Immediate

cmpwi rD, VALUE

Signed

cmpwi r0, 2

The value in r0 is compared to the value of 2. A 'if type' branch instruction will be after the cmpwi. Value in r0 and 2 are compared as 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 instruction 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' instructions:
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 rD, rA, VALUE

VALUE is any number from 1 thru 31 (0x01 thru 0x1F)

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.

If r31 is 0x12345678 before the instruction was executed...
Then r5 will equal 0x56780000 after the instruction has executed.

Each byte length of shift is equal to 8 bits. Usually, when this instruction 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 rD, rA, VALUE

VALUE is any number from 1 thru 31 (0x01 thru 0x1F)

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.

If r14 is 0x00A010FF before the instruction was executed...
Then r14 will equal 0x0000A010 after the instruction has executed.

Each byte length of shift is equal to 8 bits. Usually, when this instruction 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 rD

mtctr r11

The value in r11 is copied to the Count Register (CTR).



Move from the Count Register

mfctr rD

mfctr r11

The value in the Count Register (CTR) is copied to r11.



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 instruction is executed. Any time the count register is NOT zero, the branch to some_label will be taken. Once the count register is 0 after the bdnz is executed, the li r12, 0x0 instruction will now execute, and the 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 rD

mflr r0

The value in the Link Register is copied to Register 0.



Move To Link Register

mtlr rD

mtlr r0

The value in Register 0 is 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 second instruction shown is jumping to 'another_label'. Then the 'another_label' instructions are executed. Afterwards, a branch will be taken to some_label. However once that branch is taken, it also stores the current location/address (+4) into the Link Register. 

Once the instructions for 'some_label' are executed, you will see there is a 'blr' instruction. 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 instruction 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 instruction 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' instruction.

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 rD, VALUE (rA)

Signed

stmw r29, 0x00EC (r5)

The words of r29 thru r31 are all stored consecutively 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 the example). Also, the value of r5 plus 0x00EC must be a multiple of 0x4 (end in 0x0, 0x4, 0x8, or 0xC).

If...
r5 = 0x80455000
r29 = 0x00001000
r30 = 0x00002000
r31 = 0x00003000

Then...
The word at Address 0x804550EC would equal 0x00001000
The word at Address 0x804550F0 would equal 0x00002000
The word at Address 0x804550F4 would equal 0x00003000



Load Multiple Words

lmw rD, VALUE (rA)

Signed

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 the example). Also, the value of r5 plus 0x00EC must be a multiple of 0x4 (end in 0x0, 0x4, 0x8, or 0xC).

If...
r5 = 0x80442000
The word at Address 0x804420EC = 0x000A0000
The word at Address 0x804420F0 = 0x000B0000
The word at Address 0x804420F4 = 0x000C0000

Then Register r29 would equal 0x000A0000, Register 30 would equal 0x000B0000, and Register 31 would equal 0x000C0000.



Store String Word Immediate

stswi rD, rA, VALUE

VALUE is any number from 1 thru 32 (0x01 thru 0x20)

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 rD, rA, VALUE

VALUE is any number from 1 thru 32 (0x01 thru 0x20)

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 rD, VALUE (rA)

Signed

stwu r25, 0x0008 (r31)

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

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

When the stwu instruction 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 instruction is executed again, the 0x1000270F will be stored again to the address of 0x8000160C. The 'updating' of Register 31 will occur every time the instruction is executed.

sthu is for halfwords, stbu is for bytes



Load Word & Zero Then Update

lwzu rD, VALUE (rA)

Signed

lwzu r27, 0x1000 (r4)

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

If...
r4 = 0x80EF0050

When the lwzu instruction 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 instruction 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 instruction is excuted.

lhzu is for halfwords, lbzu is for bytes



Add Immediate Carrying

addic rD, rA, VALUE

Signed

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 rD, rA, VALUE

Signed

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. rD, rA, VALUE

Signed

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 indiciator is a shortcut for cmpwi r17, 0x0. Therefore you can then list something such as a beq as the very next instruction below the subic. instruction. Finally, the carry bit in the Fix Point Exception Register will reflect the result of the operation.



Compare Logical Word Immediate

cmplwi rD, VALUE

Logical

cmplwi r4, 0x11
bgt- some_label

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

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

cmplw rD, rA

Logical

cmplw r4, r5
bgt- some_label

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

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.



Clear Left Word Immediate

clrlwi rD, rA, VALUE

VALUE is any number from 1 thru 31 (0x01 thru 0x1F)

clrlwi r12, r0, 30

The amount of bits of the register on the left (upper) are cleared (zeroed) by the amount designated by the integer on the far right. For the example above, r0's upper/left-hand 30 bits are cleared, and the result is stored into r12.

If...
r0 is 0x80000005
Then r12 would equal 0x00000001.



Clear Right Word Immediate

clrrwi rD, rA, VALUE

VALUE is any number from 1 thru 31 (0x01 thru 0x1F)

clrrwi r4, r3, 24

The amount of bits of the register on the right (lower) are cleared (zeroed) by the amount designated by the integer on the far right. For the example above, r3's lower/right-hand 24 bits are cleared, and the result is stored back into r4

If...
r3 = 0x80000004
Then r4 would equal 0x80000000



Store Floating Single

stfs fD, VALUE (rA)

Signed

stfs f3, 0x0C10 (r31)

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



Store Floating Double

stfd fD, VALUE (rA)

Signed

stfd f0, 0x0020 (r4)

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



Load Floating Single

lfs fD, VALUE (rA)

Signed

lfs f1, 0 (r29)

The word at address of r29 plus the offset of 0 will be loaded into floating point register 1 as single precision.



Load Floating Double

lfs fD, VALUE (rA)

Signed

lfd f0, 0x8 (r3)

The word at address of r3 plus offset 0x8 will be loaded into floating point register 0 as double precision.



Floating Convert To Integer

fctiw fD, rA

fctiw f2, f6

The double precision floating point value in floating point register 6 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 f2.

If f6 = 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).

f2 will contain the result - 0xFFF80000 00000061.



Floating Convert To Integer Then Round Towards Zero

fctiwz fD, fA

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 fD, rA, rB

Signed

stfiwx f5, r11, r27

The lower 32 bits of the value in floating point register 5 will be stored to the address of r27 with using 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

The the word at Address 0x8EF11124 would equal 0x00000071.
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


Forum Jump:


Users browsing this thread: 1 Guest(s)