Basic ASM Code Debugging and Analysis for the Beginner Coder
Basic ASM Code Debugging and Analysis for the Beginner Coder

Chapter 1: Intro

After learning how to make very basic ASM Codes, the beginner coder may have trouble progressing to a higher skill level. Analyzing other already made ASM codes is one of the best ways to improve your ASM coding skills. Dolphin comes with many features to assist you.

Chapter 2: Setting up Hot Keys & Info About Other Features

Hotkeys (keyboard button shortcuts) are very useful for quick debugging. Open up your Dolphin Emulator. Under Options, select Hotkey Settings.

[Image: options.png]

There's basically only 2 hotkeys that are useful for debugging. In the general tab, there is a hotkey setting for 'Toggle Pause'.

[Image: togglepause.png]

Right click on the button for Toggle Pause to bring up the window to change its HotKey configuration.

[Image: confighotkey.png]

Whenever you bring up the Configure Input window for a Hotkey, you can select from a list or just type it in the lower larger box. Click Apply, then OK to save changes.

For the next hotkey, go to the Debugging tab.

[Image: debugtabclick.png]

There is a hotkey setting for 'Step-In'. This is by far the most important feature of debugging anything in Dolphin, and you will be using this hotkey a ton. Set this to w/e suits you, I use the 'Insert' button.

[Image: stepinto.png]

What is Step In?

'Step In' is to make Dolphin execute just one ASM instruction normally when the emulation is paused. 'Step In' is usually called 'stepping' by coders. When a coder says 'step by step' the code, they mean to debug the code utilizing the 'Step In' feature of Dolphin.

Chapter 3: Understanding How the Gecko Code Handler implements ASM Codes into Memory

According to the Gecko Documentation HERE, ASM Codes (C2 type) have the name of 'Insert ASM'. This name is misleading as it's impossible to insert within memory itself. What actually happens is this...

1. At the code's address, a branch instruction (replacing the default instruction) is placed in by the code handler (a backwards branch). View the picture below...
2. The branch instruction jumps to the first instruction of the ASM code (of the source) where the code's instructions are placed into memory by the code handler (codes are placed in memory usually around 0x800022xx thru 0x800023xx)
3. The amount to jump for the branch instruction itself is auto calculated by the code handler
4. The code instructions are thus executed. After the last instruction of the source, a branch instruction (also auto added by the code handler) will automatically jump back to the address right after the code's address, thus continuing the game's instructions.

For example let's take a look at the old historical version of the shared item code (PAL version, with 00 for the WW value) -

C27BA164 00000002
38600000 90770020
60000000 00000000

So at the address 807BA164 is a backwards branch instruction that will jump to where the code's contents reside in memory (where the code contents were dumped by the code handler). A C2 Insert ASM Code's Address (where this backwards branch instruction resides at) is called the Hook Address. So when another coder/dev mentions the term Hook Address, you now understand what they are referring to.

[Image: shareditemcodeview2.png]

To follow where any branch-type instruction leads to, right click on the instruction and choose Follow Branch.

The branch leads to the ASM code's contents (first instruction of the code highlighted in blue).

[Image: lir3zero.png]

The following is the code's contents plus the branch instruction that will jump back to where the CPU execution came from to continue running the game.

Address    Instruction
80002348  li r3, 0
8000234C  stw r3, 0x0020 (r23)
80002350  nop
80002354  b => 0x807BA168

The '00000000' word of the compiled Shared Item code is read by the code handler and the code handler knows to replace it with a branch (to address after code's address) instruction after the last instruction of the ASM source. The amount of branch at Hook Address and at the end of the code's contents, is auto-calculated by the Code Handler.

If you follow the 'b => 0x807BA168', it will lead to the instruction highlighted in blue in the following pic...

[Image: lisaftershared.png]

Let's go back to the Dolphin's Code View of the code itself but zoomed out just a bit.

[Image: c2codeview.png]

You will see there are other instructions nearby the code. In this tutorial, I simply applied just the Shared Item Code via Dolphin's Cheat Manager and nothing else. Dolphin simulates the code being contained in a GCT file (like how codes are normally loaded to a real Wii from an SD card).

The nop at 80002334 is placed by the Gecko Code Handler. I haven't gone over the entire source of the Gecko code handler personally, so I'm not sure what the purpose of this nop is.

The next two 'instructions' after that are both '(ill) 00d0code'. (ill) stands for illegal instruction. The (ill) is given to any compiled word in memory that isn't a valid PPC instruction. Dolphin will slap the (ill) tag and then display the hex contents of that particular word value.

'00d0code 00d0code' is the header of the GCT file. Every GCT file has on (if created correctly ofc). The lfs instruction at 80002340 is not an lfs instruction, it is actually the 'C27BA164' part of the Shared Item Code. Dolphin is attempting to decompile that word as a PPC instruction. The '(ill) 00000002' is what you would expect, it's the '000000002' part of the Shared Item code. Next 4 lines are the code contents plus the branch instruction to branch back to right after where the C2 code was 'hooked' to. 

The psq_st instruction at 80002358 is the 1st half of the Final Terminator of the GCT file. The final terminator of every proper GCT file is 'F0000000 00000000. Any time there is a word of null in memory, Dolphin's Code View will simply place ' --- '. Hence why you see ' --- ' at 8000235C.

Understanding how C2 Codes get executed:
This is important to know if you haven't figured this out by now. C2 ASM Codes only get executed whenever its Hook Address gets executed by the CPU. They are NOT constantly executing every time the Code Handler itself is being executed by the CPU. The amount of times different C2 codes gets executed in a specific time period varies so much & it's based on so many elements. For example, the Shared Item Code. It's address only gets executed whenever a player picks up a box. Some C2 ASM Codes may execute every frame, some only once per race, some only once during the booting of the game, it all depends.

Chapter 4. Debugging/Analyzing ASM Codes

First apply w/e code you want to debug/analyze. If the code's address gets executed during boot or is executed every frame, we need to adjust a dolphin setting (unless you don't mind the address+code getting executed multiple times before analyzing the code). At the top of the Dolphin main menu, click Options. Select 'Boot to Pause'. This will cause the game to halt when it executes its very first instruction.

Open up your Breakpoint tab/window. Set an Instruction Breakpoint using the value for the code's address. Once set, un-pause the emulation if it was paused if you used 'Boot to Pause'. After Dolphin pauses from the BP being hit, take a look at the Code View. You will be at the code's address and you will see the branch-back instruction that was mentioned earlier.

Remember the Hotkey you configured for Stepping? Use that hotkey to make the code execute one instruction at a time at w/e pace you like. When you execute the first instruction, the branch backwards jump will be preformed, and you will be at the beginning of the ASM code's instructions.

Things to note during stepping:
Whatever instruction highlighted in Green in Code View is the instruction that is GOING to execute. However, this is NOT true for any Memory Breakpoint hits! This is because Dolphin has no idea that the Memory BP was hit until after the responsible store/load instruction gets executed.

You could also look at the PC register in the Registers Tab/Window, that will also tell you what instruction is GOING to execute, but once again this does NOT apply on any Memory Breakpoint hit. PC register will function correctly once you step just one time after a Memory Breakpoint hit.

When you execute a Step-In (aka just step once), if a register gets modified, it will turn red in color on the Registers tab/window. That red register will go back to black if it's not modified if you decide to step again.

FYI, on your first emulation pause after launching a game on Dolphin, any registers not zero will start off as red color. This is on any first-time emulation pause, regardless of how the pause occurred.

Chapter 5: More Tips

To quickly set an Instruction BP on an address, simply left click to the immediate left of the Address value in code view. A grey dot will appear signaling an Instruction BP has been set for that particular address.

Need to quickly copy an address value? Right click on the address in Code View, select Copy Address.

You can also use this right-click method to quickly replace instructions. Right click on an address, you will see shortcuts to quickly replace the address's instruction with a nop or a blr. The nop feature can be really handy for beginner coders. You may not know what a blr is. If not, don't worry about that til you get to the point of learning about function calls. Or even better, use this guide on a code that has a blr instruction and analyze it to understand what it does.

You can also edit in any custom valid PPC instruction you want with the 'Replace Instruction' feature, but you will need to enter in the compiled form. If you set in a custom instruction of any kind, or a quick nop/blr, you can use the 'Restore Instruction' feature to bring back the address's original instruction.

Need to edit register values by hand? Easy to to do. Simply double click within the register you need to edit, and type in the custom value.

Btw, on the left side of the Code View is the call stack. It's a trace back of function calls. Once again, if you are a beginner coder, you don't need to worry about this as this deals with function calls.

Chapter 6: Intro to Exceptions

While stepping through your code, you may have ran into an incident where you jump to a weird spot in memory, but you have noticed the memory addresses do not start with '8', but with '0'.

You are currently on one of Broadway's Exception Routines. Whenever your code crashes, you will hit one of these Exception Routines. The true technical term for any crash is called an Exception.

Exceptions can happen for a variety of reasons, and knowing which particular Exception Routine you have landed on, can tell you a lot about what is wrong with your code.

First thing's first,you need a quick lesson on Virtual Memory vs Physical Memory. Plane jane memory that you are already familiar with is called Virtual Memory. It's a representation of Physical Memory but incorporates what is called cache. Don't worry about what Cache is, beginner's don't need to know that for ASM Codes.

Exception routines always execute in Physical Memory.

To convert a mem80/81 address form Virtual to Physical, simply change the leading '8' to '0'.
To convert a mem9 address from Virtual to Physical, simply change the leading '9' to '1'.
  • Example: 0x80345ABO ---> 0x00345AB0
  • Example: 0x921C0008 ---> 0x121C0008
  • Example: 0x817FFFFF ---> 0x017FFFFF

There are a total of 13 Exception Routines that Broadway has implemented for Wii games. However for beginner debugging we only need to go over 6.


DSI (0x00000300)
Storing/loading to/from an invalid memory address

External Interrupt (0x00000500)
Some piece of external hardware needs to temporarily halt normal operation of Broadway.

Alignment (0x00000600)
Effective Address of a stmw, lmw, or any floating point load/store instruction was not word aligned (divisible by 4).

Floating Point Unavailable (0x00000800)
Broadway currently not configured to run floating point instructions.

Decrementer (0x00000900)
When the Decrementer Register has completed decrementing. Basically there is a Timer that is always decrementing, once it hits below 0, this Exception will occur.

System Call (0x00000C00)
Whenever a 'sc' (system call) instruction is executed, Broadway will jump to the System Call Exception Routine. This routine contains cache-related tasks.


External Interrupt, Floating Point Unavailable, Decrementer, and System Call happen periodically which is normal. You may encounter these when stepping thru your codes.

Chapter 7: Setting Breakpoints in Exception Routines & srr0

If you are in a hurry and do not want to step thru all of your code but want to be notified of any Exceptions, set Instruction BPs on the following addresses before test running your code
  • 0x00000300
  • 0x00000600

These are physical addresses and must be entered in as such when setting the Instruction BPs.

If one of these Instruction BPs get triggered, there is really only one register you need to examine. And that is srr0. srr0 contains the address of the instruction that caused the Exception.

At this point, you can copy the address that's in srr0 and paste it into Code View. But there's an issue... You won't see anything listed in Code View.

That is because you are paused while Broadway is executing in Physical Memory. Thus, take your address that's in srr0, and change the leading '8' to a '0'. Plug that new address into Code View, and you should now see the instruction that is causing you a lot of trouble.

Chapter 8: Trying to Solve the cause of your Exception

DSI's are the most common type of Exceptions. If a DSI exception occurred, then the instruction located at srr0 will be a load or a store instruction. Said load/store instruction has loaded/stored from/to an invalid memory address. Be sure to check the earlier parts of your code to find out why the Source Register of the load/store instruction contains a invalid memory address.

The #1 mistake by beginners for ending up with an invalid memory address is using r0 as a source register in an instruction that treats r0 as literal zero (i.e. stw) The following will show how easy this mistake can be made...

#Set r0 to 0x80000000
lis r0, 0x8000

#Store contents of r12 to 0x80001640
stw r12, 0x1640 (r0)

And boom a DSI exception has now occurred.

If an Alignment exception occurred, check all your stmw and lmw instructions. As a Beginner, working on stmw and lmw instructions can cause some issues as it is easy to forget the rule that any Effective Address must be divisible by 0x4. This should be an easy fix if you run into this.

NOTE: There are other exceptions that could occur (such as ISI 0x400 & Program 0x700), but the reasons for these exceptions are NOT something that can be triggered accidentally from Beginner ASM Coders.

Chapter 9. Stepping Issues in regards to Exceptions

As mentioned earlier, External Interrupt, Floating Point Unavailable, Decrementer, and System Call Exceptions may occur "randomly", and they may occur while you are stepping through a code for debugging. If such an event occurs, take the address in srr0 (do NOT convert it to physical in this case), add 4 to it, and place an Instruction BP on it. Press play on Dolphin Emulator, and in a split second, you should now be at srr0+4, ready to continue stepping through the code.

Another note is that if you are at an Exception Routine, you cannot simply step thru the 'rest of it', and think you will simply jump back to your code. Your Wii game will go through a multitude of other processes after the Exception Routine before even getting close to coming back to your code. Thus, once you are something such as a DSI exception, take a look at srr0, notch down some notes, and then close the game. Trying to resume a DSI (or Alignment) exception will just result in the game halting/freezing.

Chapter 10. Conclusion

As I always tell person after person, the best way to get better at coding, is to take other people's codes (that are a little above your own skill level) and analyze them on Dolphin. Set the BPs, step by step necessary instructions, and take plenty of notes. Happy coding!
If you want, I can write out/post something like this for advanced users so you and I can both work on it
Super Mario Eclipse, what Super Mario Sunshine could've been.
Feel free, since this thread is here now I will be updating some of my more advanced threads. Such as in the Calling Function threads, including how to set BPs to allow a function to execute w/o a stepping thru the entire thing (which a beginner might try to do, lol).

One thread we need is something about working with the call stack. Another thread the site needs is anything that will cover advanced work w/ Floats.The only thread I've done on floats is basic conversion to integers.

A small quick thread on the condition register could help too, but advanced work for the CR is very rare in MKWii codes.
I will help contribute then Smile
Super Mario Eclipse, what Super Mario Sunshine could've been.
how would this work on a C0 code?
Great question. It's a bit tedious. For the specific C0 code you wanna step thru, make sure it's your very first code in your Cheat-Manager. Then in Dolphin, set the Boot to Pause flag (can't remember where this is at). Make sure your codes are applied, boot your game. The emulation will auto pause on the very first executable instruction of the game.

Then go to 0x800018A8 in Code View. This is the start of the Code Handler. Once at 0x800018A8, start to scroll down and search for the following two instructions..

mtlr r15

These are the instructions that the Handler uses to execute all C0 Codes. Once you find these two instructions, set an Instruction BP on blrl. Unpause the emulation. Once that BP gets hit, your emulation will pause itself then you need to simply use 'Step-In' just one time. You are now at the first instruction of your C0 Code. Set a new BP on said instruction and remove the previous BP. Thus you only get a BP hit on that specific C0 code again if you decide to let the emulation run again.

Forum Jump:

Users browsing this thread: 1 Guest(s)