Inline ASM HBC Tutorial
Inline ASM HBC Tutorial

All credits to for original tutorial. Wiibrew tutorial is HERE

I've made a few apps using Inline PowerPC Assembly for very basic stuff. This isn't really useful for apps in general as you want to learn C and C++, but nonetheless here's a tutorial utilizing Inline ASM for HBC apps.

Chapter 1: Installing DevkitPro PPC

If you don't have DevkitPro PPC, you need to install it. For Windows and Ubuntu linux, there are tutorials literally everywhere on the Web. If you happen to use Debian Linux like me, I wrote a good tutorial for installation HERE.

Chapter 2: Changes to default project

Make a copy of the Hello World Wii Project (examples/Wii/template), and paste it to a new directory. Go ahead and rename the 'template' directory (the one in your new directory) to assembler. Within your /assembler folder, delete the template.pnproj file, you don't need it.

The Makefile at /assembler needs to be modified. Open up the Makefile on your preferred notepad/text-editor and find this...

# options for code generation


LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map

Depending on your devkit version, this contents here may slightly differ. You need to add a comment (hash tag symbol) on the 'CFLAGS' line. like this..

#CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE)

After that edit, add the following line (place it right above the CFLAGS line)...

CFLAGS = -save-temps -Wall $(MACHDEP) $(INCLUDE)

If you did everything correctly, the Makefile (the portion showed earlier), should look like this..

# options for code generation

CFLAGS = -save-temps -Wall $(MACHDEP) $(INCLUDE)
#CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE)

LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map

Save your edits, close the file.

Chapter 3: Setting up new Default Project

The edits are made. Now compile the project. For linux, it would be something like this...

cd /path/to/the/folder/assembler

When the project gets compiled there will be a new directory present... (/assembler/build). Within the build directory, you should see the template.s file, this is our Inline ASM file. Go ahead and delete the following files


And also delete the newly created dol and elf files. Remember that line for CFLAGS you added to the makefile? Go ahead and comment it out. Uncomment the original CFLAGS line. Now you always have a default Inline ASM project. BACK THIS UP somewhere safe.

Chapter 4: Writing some Inline ASM

We are now actually going to do some Inline ASM work to create a very basic new project. Before we do that, let's make a small edit to the project. Open up the /build/template.s file.

Change "Hello World!" to "Hello ASM!!!". And yes, make sure you use 3 total exclamation marks.

Save changes. Open the /source/template.c file and make the same changes to "Hello World!". Save changes.

Now it's time to write some Inline ASM. Open up template.s. Scroll down until you see something like this (yours may slightly differ)...

bl WPAD_ScanPads
li 3,0
bl WPAD_ButtonsDown
stw 3,8(31)
lwz 9,8(31)
rlwinm 9,9,0,24,24
cmpwi 7,9,0
beq 7,.L3
li 3,0
bl exit

This is the chunk of ASM responsible for constantly loading the Wii Remote button values and seeing if the Home button is pressed. If it is (r9 not equal to 0), the li 3,0 instruction (only argument upcoming function) is executed and then the exit function is called, thus exiting back to HBC.

We will modify this chunk of ASM to shutdown the Wii instead of exiting to HBC. The Wii has some GPIO lines which you can read about HERE, which we can write basic ASM for to execute a shutdown (NOTE: This will only work on HBC versions 1.1.0 or later or else there may be a permissions error and the shutdown won't be executed).

Here's a small snippet of ASM to shutdown the Wii....

lis r3, 0xCD80 #Set GPIO_OUT upper 16 bits
lwz r4, 0x00E0 (r3) #Load Pin Connection word value from GPIO_OUT
ori r4, r4, 0x0002 #Toggle the SHUTDOWN Pin
stw r4, 0x00E0 (r3) #Update the GPIO_OUT Pins

Now add this snippet of ASM right underneath the 'beq' instruction (the branch taken if the Home button is NOT pressed). The chunk of ASM should now look like this...

bl WPAD_ScanPads
li 3,0
bl WPAD_ButtonsDown
stw 3,8(31)
lwz 9,8(31)
rlwinm 9,9,0,24,24
cmpwi 7,9,0
beq 7,.L3

    lis r3, 0xCD80 #Set GPIO_OUT upper 16 bits
    lwz r4, 0x00E0 (r3) #Load Pin Connection word value from GPIO_OUT
    ori r4, r4, 0x0002 #Toggle the SHUTDOWN Pin
    stw r4, 0x00E0 (r3) #Update the GPIO_OUT Pins

li 3,0
bl exit

Onto compiling...

Chapter 5: Compiling the Inline ASM Project

We simply cannot go ahead run make on the Makefile to have this project compiled. We need do some extra steps, which is creating an object file (.o file) from our Inline ASM file. This is done using devkit's binutils. For linux, something like this would be executed in your terminal..

cd /path/to/your/binutils #(devkitpro/devkitPPC/bin)

./powerpc-eabi-as -mregnames -mbroadway /path/to/assembler/build/template.s -o /path/to/assembler/build/template.o

cd /path/to/assembler


The project will now compile. Rename the dol file to boot.dol.

Chapter 6: Final Tests

After renaming the dol file. Throw in any xml and png file to make a quick app out of the project. Place the project in the apps folder of your SD/USB device. Launch the app.

Side note: Make sure your XML file has the tag <ahb_access/> tag(right before the final tag of </app>). These is needed to allow Broadway to have full permissions or else the Wii shutdown function won't work.

If you are too lazy to find or make an xml, here's a template you can use, you will still need to get an icon.png btw...

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<app version="1.1">
<name>NAME OF PROGRAM</name>
<long_description>MORE STUFF</long_description>

You will see the Hello ASM!!! message. Now press the Home button on your Wii Remote. The Wii will shutdown. Congratz! And there ya go, a quick example of how to run very basic Inline ASM instructions on a HBC project. Happy coding!

Chapter 7: Extra Stuff

In this snippet of code, this is the button check for the Wii Remote to see if HOME button was pressed to exit to HBC

bl WPAD_ScanPads
li 3,0 #Arg for WPAD_ButtonsDown
bl WPAD_ButtonsDown
stw 3,8(31) #Buttons Down returned in r3, Store it
lwz 9,8(31) #Load Buttons-Down into r9
rlwinm 9,9,0,24,24 #Clear all bits except HOME button bit
cmpwi 7,9,0 #Check r9 vs 0, use cr7
beq 7,.L3 #If HOME button bit is 0 (NOT pressed), continue to .L3 (video syncing and keeping app running)

The Rotation instruction shows bit 24 is for the HOME button. Here is all the Wii Remote button bits if you ever need them...
Bits 16 thru 18 = unused
Plus = Bit 19 (0x00001000)
Up = Bit 20 (0x00000800)
Down = Bit 21 (0x00000400)
Right = Bit 22 (0x00000200)
Left = Bit 23 (0x00000100)
Home = Bit 24 (0x00000080)
Bits 25 & 26 = unused
Minus = Bit 27 (0x00000010)
A = Bit 28 (0x00000008)
B = Bit 29 (0x00000004)
1 = Bit 30 (0x00000002)
2 = Bit 31 (0x00000001)

And if a nunchuck is attached, here's its extra bits
C = Bit 14 (0x00020000)
Z = Bit 15 (0x00010000)

Fyi, for anything Classic Controller related, you don't need to add any extra functions to call/check, Wii Remote attachments are configured automatically, simply just use these bits. Keep in mind that the nunchuck attachment bits (14 and 15) are also used by the Classic Controller)

Right = Bit 0 (0x80000000)
Down = Bit 1 (0x40000000)
L = Bit 2 (0x20000000)
Minus = Bit 3 (0x10000000)
Home = Bit 4 (0x08000000)
Plus = Bit 5 (0x04000000)
R = Bit 6 (0x02000000)
Bit 7 = Unused
ZL = bit 8 (0x00800000)
B = Bit 9 (0x00400000)
Y = Bit 10 (0x00200000)
A = Bit 11 (0x00100000)
X = bit 12 (0x00080000)
ZR = bit 13 (0x00040000)
Left = bit 14 (0x00020000)
Up = bit 15 (0x00010000)

If desired you can easily add GCN compatibility. You can do this via adding the basic functions in C then modifying via Inline or do everything from scratch in the inline file.

Via C file:
Add this right underneath WPAD_Init
// Initialise GCN

And in the part of the C file that deals with the WPAD scan and exiting to HBC via HOME button, modify it something like this...
// Call WPAD_ScanPads each loop, this reads the latest controller states

        // WPAD_ButtonsDown tells us which buttons were pressed in this loop
        // this is a "one shot" state which will not fire again until the button has been released
        u32 pressed = WPAD_ButtonsDown(0);
        // Call PAD_ScanPads each loop, this reads the latest GCN controller states
        u32 GCNpressed = PAD_ButtonsDown(0);

        // We return to the launcher application via exit
        if ( pressed & WPAD_BUTTON_HOME ) exit(0);
        if ( GCNpressed & PAD_TRIGGER_START ) exit(0);

        // Wait for the next frame

Afterwards, just compile with the makefile modified to allow you to edit the .s inline file to what you need.

Via Inline:
If you don't want to modify the C file, just do everything via Inline. In your Inline file, add a "bl PAD_Init" right underneath the "bl WPAD_Init". Then edit the button scanning portion to something like this...

bl WPAD_ScanPads
li 3,0
bl WPAD_ButtonsDown
stw 3,8(31)
bl PAD_ScanPads #scan the GCN
li 3,0
bl PAD_ButtonsDown #get what buttons are pressed in the GCN
stw 3,12(31) #safe to do. Store GCN buttons

Then do what you need with the WPAD and PAD button values that are stored in reference to r31.

And here are all the GCN button bit values...
Start = bit 19 (0x00001000)
Y button = bit 20 (0x00000800)
X button = bit 21 (0x00000400)
B button = bit 22 (0x00000200)
A button = bit 23 (0x00000100)
bit 24 unused
L = bit 25 (0x00000040)
R = bit 26 (0x00000020)
Z = bit 27 (0x00000010)
Up = bit 28 (0x00000008)
Down = bit 29 (0x00000004)
Right = bit 30 (0x00000002)
Left = bit 31 (0x00000001)

Here are some tips/tricks to make printf not so boring...

Start Console (always included in the source by default, simply posted here for completeness)

Enter into New Line

Clear Console, Move cursor back to very top left (note: this goes up to being partially out of screen so further messages afterwards start with a double enter \n\n)

Set Font Color (XX = color)

30 = Black
31 = Red
32 = Green
33 = Yellow
34 = Blue (not useful as it's very faded/dull)
35 = Purple
36 = Cyan
37 = White/Default

You can also set the Fill Color. Just add 10 to font color XX value, string used is same as font color.

Forum Jump:

Users browsing this thread: 1 Guest(s)