Inline ASM HBC Tutorial
#1
Inline ASM HBC Tutorial



All credits to WiiBrew.org 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...

Code:
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------

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

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..

Code:
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------

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

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/source
make

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

template.d
template.elf.map
template.i
template.o

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)...

Code:
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....

Code:
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...

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

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

cd /path/to/assembler

make

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.

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

Code:
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) #(Redundant instruction lol devkit); Load Buttons-Down into r9
rlwinm 9,9,0,24,24 #Clear all bits except HOME button bit
cmpwi 7,9,0 #(Lol devkit using cr7 all the time)
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 other Wii Remote button bits if you ever need them...
Minus = Bit 27
Plus = Bit 19
A = Bit 28
B = Bit 29
1 = Bit 30
2 = Bit 31
Up = Bit 20
Down = Bit 21
Left = Bit 23
Right = Bit 22

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.

Home = bit 4
A = bit 11
B = bit 9
Minus = bit 3
Plus = bit 5
X = bit 12
Y = bit 10
Up = bit 15
Down = bit 1
Left = bit 14
Right = bit 0
ZL = bit 8
ZR = bit 13
L = bit 2
R = bit 6

And if a nunchuck is attached, here's its extra bits
Z = bit 15
C = bit 14



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
Code:
// Initialise GCN
    PAD_Init();

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...
Code:
// Call WPAD_ScanPads each loop, this reads the latest controller states
        WPAD_ScanPads();

        // 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
        PAD_ScanPads();
       
        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
        VIDEO_WaitVSync();

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...
A button = bit 23
B button = bit 22
Y button = bit 20
X button = bit 21
Start = bit 19
Up = bit 28
Down = bit 29
Left = bit 31
Right = bit 30
Z = bit 27
L = bit 25
R = bit 26



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)
\033[2;0H

Enter into New Line
\n

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)
\x1b[2J

Set Font Color (XX = color)
\x1b[XXm

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.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)