Difference between revisions of "Assembly Code"

From Custom Mario Kart
Jump to navigation Jump to search
(Added a primer on PPC ASM which I hope will help people wanting to get into ASM modding on Wii.)
m (Remove links to Broadway Manual.)
Line 32: Line 32:
 
Branching instructions affect the flow of machine code instructions on the processor. Instructions are stored in some memory outside the processor (MEM1 in the case of the Wii). Normally, the processor will retrieve each machine code instruction, execute it, then move on to the next instruction. Each machine code instruction is exactly 4 bytes long in PowerPC, so this corresponds to stepping through memory by adding 4 to the address. A branching instruction changes this by telling the processor where to look for the next instruction explicitly. This replaces the implicit next instruction address obtained by adding 4 to the current instruction address. <code>blr</code> ('''b'''ranch to '''l'''ink '''r'''egister) causes the processor to instead use the current value of the <code>lr</code> as the address for the next instruction. The <code>lr</code> is just a 32 bit special purpose register which a small number of arithmetic and branching instructions can modify. Thus, we would need to know the value of the <code>lr</code> to know what instruction would execute next in the example. The redirection is 'permanent' so after executing the instruction at the address given by the <code>lr</code> it would then add 4 to get the next address and so on, unless it encountered another branch.
 
Branching instructions affect the flow of machine code instructions on the processor. Instructions are stored in some memory outside the processor (MEM1 in the case of the Wii). Normally, the processor will retrieve each machine code instruction, execute it, then move on to the next instruction. Each machine code instruction is exactly 4 bytes long in PowerPC, so this corresponds to stepping through memory by adding 4 to the address. A branching instruction changes this by telling the processor where to look for the next instruction explicitly. This replaces the implicit next instruction address obtained by adding 4 to the current instruction address. <code>blr</code> ('''b'''ranch to '''l'''ink '''r'''egister) causes the processor to instead use the current value of the <code>lr</code> as the address for the next instruction. The <code>lr</code> is just a 32 bit special purpose register which a small number of arithmetic and branching instructions can modify. Thus, we would need to know the value of the <code>lr</code> to know what instruction would execute next in the example. The redirection is 'permanent' so after executing the instruction at the address given by the <code>lr</code> it would then add 4 to get the next address and so on, unless it encountered another branch.
  
A full listing of all instructions supported by the Wii's processor can be found in Chapter 12 of the [//thewiiu.com/index.php?app=core&module=attach&section=attach&attach_id=1576 IBM Broadway RISC Microprocessor User Manual], along with an explanation of the behaviour of each. Chapter 2 is also particularly useful for assembly code programmers as it explains the basic operation of the processor from a programmer's perspective. That manual references [//www.nxp.com/files/product/doc/MPCFPE32B.pdf Programming Environments Manual for 32-Bit Implementations of the PowerPC Architecture] which is a more generic description of PowerPC not specific to the Broadway processor found in the Wii. It also contains an instruction set listing in Chapter 8, which omits the Wii specific instructions. It also has a useful Chapter 2 which explains how PowerPC processors work from a programmer's perspective.
+
A listing of most instructions supported by the Wii's processor can be found in Chapter 8 of the [//www.nxp.com/files/product/doc/MPCFPE32B.pdf Programming Environments Manual for 32-Bit Implementations of the PowerPC Architecture], along with an explanation of the behaviour of each. Chapter 2 is also particularly useful for assembly code programmers as it explains the basic operation of PowerPC processors from a programmer's perspective.
  
 
== Tools ==
 
== Tools ==
Line 51: Line 51:
 
== See Also ==
 
== See Also ==
  
* [//thewiiu.com/index.php?app=core&module=attach&section=attach&attach_id=1576 IBM Broadway RISC Microprocessor User Manual] - the Wii's processor manual.
 
 
* [//www.nxp.com/files/product/doc/MPCFPE32B.pdf Programming Environments Manual for 32-Bit Implementations of the PowerPC Architecture] - a generic PowerPC processor manual.
 
* [//www.nxp.com/files/product/doc/MPCFPE32B.pdf Programming Environments Manual for 32-Bit Implementations of the PowerPC Architecture] - a generic PowerPC processor manual.
 
* [//en.wikipedia.org/wiki/Assembly_language Wikipedia's article] on Assembly Code.
 
* [//en.wikipedia.org/wiki/Assembly_language Wikipedia's article] on Assembly Code.
 
* [//en.wikipedia.org/wiki/PowerPC Wikipedia's article] on PowerPC.
 
* [//en.wikipedia.org/wiki/PowerPC Wikipedia's article] on PowerPC.

Revision as of 21:59, 17 September 2017

Assembly code (abbreviated to ASM) is a type of programming language which is directly translatable to machine code. Machine code is typically directly understood/interpreted by a physical circuit called a processor. In the context of the Wii references to ASM typically refer specifically to PowerPC assembly code as PowerPC machine code is used by the Wii's Broadway processor and is the format of Mario Kart Wii's code on the game disk.

The machine code for Mario Kart Wii is stored in the files main.dol and StaticR.rel. The game was programmed in the programming languages C and C++ and then a compiler (Metrowerks CodeWarrior) translated this code into machine code. Reversing the process of compilation is very difficult so game mods are typically added by writing in ASM or GCT code.

Machine Code

Machine code refers to the binary code which is run by computer processors. It is generally very hard for humans to read and understand. Assembly code is a human readable translation of machine code. There is typically a one to one correspondence between assembly code and machine code. That is to say, one line of assembly code corresponds to one instruction of machine code. Thus, the two terms (machine code and assembly code) are commonly used interchangeably. When working with machine code, most people prefer to translate it to assembly code, edit the assembly code, then translate that back to machine code. Programs that translate assembly code to machine code are called assemblers and programs that translate machine code to assembly code are called disassemblers.

Dialects

In comparison to higher level programming languages (C, C++, C#, Java, Python, JavaScript, etc) the choice of which dialect of machine/assembly code dialect to use is forced by which processor will run the code. Each processor will generally only be capable of running one dialect of machine code, and will simply be unable to use code written for other processors. This is one of the main disadvantages of assembly code, and why such higher level languages were invented.

ARM Assembly Code

ARM assembly code is the format of assembly code used by the Wii's Starlet processor. This processor only runs the Wii's IOS operating system, and so consequently no game code is ARM assembly code.

PowerPC Assembly Code

PowerPC (PPC) assembly code is the format of assembly code used by the Wii's Broadway processor. It supports most common PowerPC instructions, but also some special unique ones specific to the Wii. This processor runs Wii games and therefore all of the assembly code in Mario Kart Wii is PowerPC Assembly Code. Each line (instruction) of PowerPC assembly code is written as a mnemonic followed by a number of arguments. For example:

lis r3, 0x8000
lwz r4, 0(r3)
stw r4, 0x3180(r3)
blr

The above example contains four instructions, one per line. The first instruction has the mnemonic lis and takes two arguments (r3 and 0x8000). The second and third instruction have mnemonics lwz and stw and both take three arguments (r4, 0, r3 and r4, 0x3180, r3 respectively). The final instruction has mnemonic blr and takes no arguments. The number, order and format of the arguments to an instruction depend on the mnemonic. That is to say, every lis instruction will take two arguments, the first of which is a register and the second of which is a 16 bit integer, with a comma between them. A register is a small piece of memory (32 bits in PowerPC). There are 32 general purpose registers in PowerPC labelled r0, r1, ..., r31. These are mostly identical but r0 is slightly special. However, by convention the ABI gives specific jobs to each register so mixing assembly code from different sources is more likely to work.

When translated to machine code, a PowerPC processor would be able execute these instructions. The effect of each depends on the mnemonic and the arguments. There are three main types of instruction; arithmetic, memory and branching. After executing each instruction the processor then moves on to the next instruction sequentially, except in the case of branches. Arithmetic instructions like the lis in the above example perform some simple mathematical computation between their arguments and then store the result in a register. Typically the first argument is the destination register; where to put the result, and the remaining arguments are the inputs to whatever calculation is being performed. Thus, in the example, the first instruction means "perform an lis on 0x8000 and store the result in r3. lis is short for "load immediate shifted" and the effect of this is to multiply the input by 0x10000 corresponding to a left bit shift of 16. Thus, the result of this instruction will be 0x80000000 and so after the instruction that will be the value in r3.

Memory instructions move data into (loads) or out of (stores) the processor. In the above example, lwz is a load and stw is a store. When moving data, the processor must always know where to move it from or to. This is called the address. On PowerPC each address is a 32 bit number. Which addresses correspond to what data is a property of the whole system, not just the processor. On the Wii for example, addresses 0x80000000 to 0x817fffff correspond to MEM1; a 24 MiB RAM chip. Each number in that range corresponds to exactly one byte of MEM1. An instruction may affect multiple bytes of this chip at once, for example the lwz and stw instructions affect 4 consecutive bytes of MEM1. In the example, the lwz instruction retrieves 4 bytes of data from MEM1. The behaviour of the lwz (load word and zero) is to add 0 to the value in r3 (which is 0x80000000 due to the lis instruction) and then send that address to MEM1. MEM1 will reply by sending 4 bytes back starting at it's first byte (at 0x80000000) and ending at it's fourth byte (at 0x80000003). This 4 byte (32 bit) reply will then be stored in r4. The next instruction in the example is stw (store word). It computes an address similar to the lwz by adding 0x3180 to the value in r3 (which is still 0x80000000) to produce the address 0x80003180. It will then send this to MEM1 along with the value in r4 (which came from the lwz). MEM1 will then replace the 4 bytes starting at 0x80003180 with the value from r4. Thus, if a later load instruction accessed the same bytes, it would find the updated values. No other actual affect occurs on the processor itself in this case, so neither r3 nor r4 are changed by the stw instruction.

Branching instructions affect the flow of machine code instructions on the processor. Instructions are stored in some memory outside the processor (MEM1 in the case of the Wii). Normally, the processor will retrieve each machine code instruction, execute it, then move on to the next instruction. Each machine code instruction is exactly 4 bytes long in PowerPC, so this corresponds to stepping through memory by adding 4 to the address. A branching instruction changes this by telling the processor where to look for the next instruction explicitly. This replaces the implicit next instruction address obtained by adding 4 to the current instruction address. blr (branch to link register) causes the processor to instead use the current value of the lr as the address for the next instruction. The lr is just a 32 bit special purpose register which a small number of arithmetic and branching instructions can modify. Thus, we would need to know the value of the lr to know what instruction would execute next in the example. The redirection is 'permanent' so after executing the instruction at the address given by the lr it would then add 4 to get the next address and so on, unless it encountered another branch.

A listing of most instructions supported by the Wii's processor can be found in Chapter 8 of the Programming Environments Manual for 32-Bit Implementations of the PowerPC Architecture, along with an explanation of the behaviour of each. Chapter 2 is also particularly useful for assembly code programmers as it explains the basic operation of PowerPC processors from a programmer's perspective.

Tools

  • GNU Binutils include an assembler and disassembler. Specifically, in devkitPro is an assembler and disassembler for PowerPC and ARM.
  • ASMWiiRd is a Windows GUI application for converting between PowerPC assembly code and GCT codes with assembly code embedded inside.
  • The Dolphin emulator when started with the "/D" command line option can display, pause and edit the assembly code of the emulated game.

To use devkitPro's Binutils to assemble input.asm (text document with assembly code) to output.bin (a file containing the raw machine code) the commands would be:

powerpc-eabi-objdump -mregnames -m750cl input.asm -o temp.elf
powerpc-eabi-objcopy -O binary temp.elf output.bin

Note that there is no easy way to set the loaded address of the instructions so only relative branching instructions should be used (i.e. don't expect b 0x80000000 to assemble correctly).

To use devkitPro's Binutils to disassemble input.bin (a file containing raw machine code) the command would be:

powerpc-eabi-objdump -b binary -m powerpc:750 -M 750cl -D -EB --adjust-vma=0x80000000 test.bin 

Note that some instruction's arguments depend on their address, so you can change the value of adjust-vma to be the loaded address of the first instruction.

See Also