----------------Breakdown by PoptartHunter, Clay10, Romaap, Dazoc, and ChatGPT----------------
I made this after watching the old BSOD video(episode 24) to rejog my memory. Can still be found thanks to the internet archive. Anyhow because of that I decided to use the code created in that video as an example
to find the video I referenced you can use your search engine of choice and search for "Bastard Sons of Dial-Up" and you'll want to watch the first segment of Episode 24. I don't want to link the video as I don't know the rules of the website or if the footage is copywrited but it is easy to find
This breakdown covers the code made in BSOD E24 and also dives into asm unrelated to that video. I didn't write much. Mostly tossed it all together for easy reference(Dazoc)
Hope this helps and if you have any questions I'll do my best to answer them
I made this after watching the old BSOD video(episode 24) to rejog my memory. Can still be found thanks to the internet archive. Anyhow because of that I decided to use the code created in that video as an example
to find the video I referenced you can use your search engine of choice and search for "Bastard Sons of Dial-Up" and you'll want to watch the first segment of Episode 24. I don't want to link the video as I don't know the rules of the website or if the footage is copywrited but it is easy to find
This breakdown covers the code made in BSOD E24 and also dives into asm unrelated to that video. I didn't write much. Mostly tossed it all together for easy reference(Dazoc)
- WHAT IS A POINTER?:
- Pointers [Clay10]
What do pointer codes do exactly? Pointers read the value at an address and if the address contains a valid pointer address, it will add a value to the offset. Many of you may look at addresses in memory viewer and see values like 80721748 at 81205718. 80721748 would be the pointer, and a value would be added to that.
Simple pointer code outline using direct ram writes -
48000000 TTTTTTTT #load address T into pointer
14YYYYYY XXXXXXXX #Y = value to add to value at T. X = value to write at Y + T
E0000000 80008000 #endif
Now to compile this into a working code.
48000000 81205718 #loads 81205718 (the value at 81205718 is the pointer)
140002E9 3F800000 #adds
000002E9 to the value at 81205718 and writes 3F800000 to the result
E0000000 80008000
Most codetypes will work in the same way as the 04 codetype. You just have to add 10 to the codetype. ASM for example looks like this -
48000000 81205718 #load into pointer
D20002E9 00000001 #C2 changed to D2. Add 2E9 to the pointer at 81205718 and insert 00000001 line(s) of ASM instruction(s) to the result.
60000000 00000000 #asm nop
E0000000 80008000 #endif
To recap: pointers add a value to the pointer(value) at a given address. You can use any codetype that supports pointers, just add 10 to the codetype and go about making the code as you normally would.
- WHAT IS ASM?:
- Basic ASM [Romaap]
Introduction to ASM
First you need to know, what is assembly?
Well, assembly is a low-level programming language. (languages like C and Java are high-level programming languages)
An example of an assembly instruction:
li rA, value
What this does is, it tells the Wii to load value to rA. (li means 'Load immediate')
But what is rA?
rA is a register, the Wii has 31 registers.
A register is sort of a temporary space to store values, like RAM but the registers are easier to access by the CPU.
So if we have li r16, 0x14 then the Wii will write 0x14 to r16.
Another example is 'Add immidiate':
addi rD, rA, value
What this does is add value to the value at rA and store it in rD.
So if we have addi r16, r20, 0x3 and the value of r20 is 0x2 then 0x5 is stored to r16.
(This is the same as 'Subtract immediate': subi rD, rA, value)
rD is in most examples the destination register, the destination register is almost always the first register.
The other registers are not altered (in this example r20 stays 0x2).
Another example is 'Subtract':
sub rD, rA, rB
This one subtracts the value in rB from rA and store it in rD (and again, only rD is altered).
So if we have sub r16, r20, r21 and the value of r20 is 0x9 and r21 is 0x3 then 0x6 will be stored to r16.
(This is the same as 'Add': add rD, rA, rB)
The last example is 'Store word', which will store the value in a register to the RAM:
stw rS, d(rA)
This will store the value in rS to the address in rA + d.
So if we have stw r20, 100(r0) and the value of r20 is 0xA and r0 is 0x80605040 then 0xA will be stored to 0x806050A4 (0x80605040 + 100 (0x64))
If you want to load a value from an address then you use 'Load word and Zero':
lwz rD, d(rA) which works like stw but the opposite, the value from the address in rA + d will be stored to rD.
This concludes the introduction to ASM, I hope you understand it
- BSOD E24 CODE:
- [RMGP01] Super Mario Galaxy (Europe) (En,Fr,De,Es,It)
Infinite Health [dexter0]
48000000 806B7B40
14000380 00000003
E0000000 80008000
Line 1: Load into Pointer Address - Load &value into the pointer address.
Line 2: Write/Fill - Writes the value of 3 to + 1 consecutive byte-sized addresses, starting with the address 0x380.
Line 3: Full Terminator - Clears the code execution status. If 0x8000 isn't zero, then set the base address to 0x80000000. If 0x8000 isn't zero, then set the pointer address to 0x80000000.
Pointer Address
48000 : po(pointer address) = [XXXXXXXX]
CST2: 32bits Write
14______ XXXXXXXX : 32bits ram write (po) writes XXXXXXXX at po+address
CST0 : Full Terminator
E0000000 XXXXYYYY : full terminator
It clears the code execution status.
If XXXX<>0, ba = 0xXXXX0000
If YYYY<>0, po = 0xYYYY0000
"806B7B40" - pointer address
"380" - pointer offset
"3" - mario's health
Format Example [Creator]
48000000 XXXXXXXX
14YYYYYY ZZZZZZZZ
E0000000 80008000
X - pointer address
Y - pointer offset
Z - 32bit hex value
- ASM USING POINTER:
- Format Example [Creator]
48000000 XXXXXXXX
D2YYYYYY ZZZZZZZZ
WWWWWWWW WWWWWWWW
E0000000 80008000
X - pointer address
Y - pointer offset
Z - lines of asm in 32bit
W - asm code
Below you will see where D2 came from. C2 is used for normal asm written at the base address while D2 is written to a pointer
CST1 : Insert ASM code in the game
C2XXXXXX NNNNNNNN = insert instructions at XXXXXXXX+ba
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ ZZZZZZZZ
60000000 00000000
This code will replace the instruction at ba+XXXXXXXX with a branch that will point to ZZZZZZZZ. The replaced is not saved, the code creator must then put it in his code manualy (if needed).
Also, the instruction MUST end with ONE 00000000, because the code handler will add a "b (ba+XXXXXX)" instruction there. If your asm code fills all the line, add a 60000000 00000000 under it
(and count this line in NNNNNNNN).
D2XXXXXX NNNNNNNN = insert instructions at XXXXXXXX+po
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ 00000000
This code will replace the instruction at po+XXXXXXXX with a branch that will point to ZZZZZZZZ. The replaced is not saved, the code creator must then put it in his code manually (if needed). Also, the instruction MUST end with 00000000, because the code handler will add a "b (po+XXXXXX)" instruction there. If your asm code fills all the line, add a 60000000 00000000 under it (and count this line in NNNNNNNN).
- HOW TO FIND A POINTER ADDRESS:
- *USING WIIRD* though works roughly the same for other memory search engines like Gecko.Net
Find the address for your desired outcome on that level/stage as you would for a code that doesn't require a pointer
Right click > Pointer 1 > Pointer Search > Dump
Repeat on the next level/stage for pointer 2
use the search function under Pointer Search after both memory dumps are made for separate levels and dump file directories are confirmed
After the search is complete you should see addresses with their offsets under "Best Results" EXAMPLE: [81C6A26D]+460
Copy the addresses and search them under Memory Viewer one at a time
They should give you an address that you can add the given offset to and poke to test if that address(from best results) is the pointer you're looking for
If it works than the address under Best Results that gave you your wanted outcome is your Pointer Address and the number beside it is your Pointer Offset
- MORE DETAIL ON ASM:
- Basic C2 (ASM) [PoptartHunter]
In this tutorial I will teach you how to simply use the C2 codetype effectively, you'll need a USB gecko for this.
C2's function is to insert asm at a specified address. In order to get this assembly address, you will need to set a write breakpoint on whatever you are trying to make. Be it health, ammo, etc. Set the breakpoint, then do something to lose some of the specified item. If it's the address for health, set a write breakpoint on it, then lose some health to trigger the breakpoint. If it's ammo, set a write breakpoint on your ammo address, then lose some ammo to trigger the breakpoint.
For this tutorial, we are going to use infinite ammo as the example. Say we set the breakpoint, we get it to trigger shooting, then we get the asm address 80304820.
Look in the breakpoint tab in the little box (you'll know what i'm talking about if you have Gecko.net and a usb gecko).
Let's say the instructions for the address 80304820 are stw r0,0(r12). First you'll want to look at r0 in the little box, and look at the value in it. The value should be whatever ammo count you have after shooting the gun. So say we had 64 bullets (100 in hex) then we shoot one to trigger the breakpoint, the value at r0 in the little box should be 63 (99 in hex).
After that, look at r12 in the box. The address in r12 should be the same as your normal address to your ammo.
So, we know how this address works basically now. The stw instruction takes the value in r0 and writes it to the address in r12. Let's start writing our assembly!
first, we want to overwrite the value that is in r0 with something else, since that is the ammo count. For this, we'll need to use the li instruction, which means "load immediate". We're going to do this:
li r0,999
This instruction will put the value 999 into r0, simple right?
Next we're going to have to find a way to make 999 be written to the address in r12. This is simple, remember our instruction earlier? stw r0,0(r12)? That's exactly what we will be doing here.
li r0,999 stw r0,0(r12) nop
What this does is, it will overwrite the default value in r0 (your ammo count) with the value 999 by using the li instruction to put it there. The stw instruction will take the value in r0 (which is 999) and write it to the address in r12 (our address for ammo count).
What does the nop instruction do you ask? Nothing. Yes, nothing. We put it there because a C2 code cannot end in an even number of lines or it will freeze.
Now that we've gotten our assembly all typed up, let's put it into asm <>wiird and convert it to a code we can use.
Here's our finished code!
Infinite Ammo [HexWire]
C2304820 00000002
380003E7 900C0000
60000000 00000000
ASM Continuation for PoptartHunter's guide
This section below is brought to you by ChatGPT! THE ROBOTS ARE TAKING OVER!
Format Example [Creator]
48000000 XXXXXXXX
D2YYYYYY 00000002
380003E7 900C0000
60000000 00000000
E0000000 80008000
X - pointer address
Y - pointer offset
380003E7: This is a 32-bit hexadecimal number representing a machine code instruction.
First, convert it to binary: 00111000000000000000001111100111
Break it down according to PowerPC assembly format:
Opcode (6 bits): 001110 (This corresponds to the opcode for the li instruction, which means "load immediate".)
RA (5 bits): 00000 (Register RA, which specifies the target register, in this case, r0.)
RB (5 bits): 00000 (Register RB is not used for this instruction.)
D (16 bits): 0000000000000011 (This is the immediate value to load into register r0.)
So, 380003E7 translates to:
assembly
li r0, 999
900C0000: Another 32-bit hexadecimal machine code instruction.
Convert to binary: 10010000000011000000000000000000
Break it down:
Opcode (6 bits): 100100 (This corresponds to the opcode for the stw instruction, which means "store word".)
RA (5 bits): 00000 (Register RA, typically the source register holding the data to store, in this case, r0.)
RB (5 bits): 11000 (Register RB, which is the base register holding the memory address to store the word.)
D (16 bits): 0000000000000000 (This is the offset or displacement, which is 0 in this case.)
So, 900C0000 translates to:
assembly
stw r0, 0(r12)
60000000: Another 32-bit hexadecimal machine code instruction.
Convert to binary: 01100000000000000000000000000000
Break it down:
Opcode (6 bits): 011000 (This corresponds to the opcode for the nop instruction, which means "no operation".)
Remaining bits: All 0s indicate no additional parameters or operands.
So, 60000000 translates to:
assembly
nop
00000000: Finally, another 32-bit hexadecimal machine code instruction.
This is all zeros, indicating a nop instruction again.
So, 00000000 also translates to:
assembly
nop
Combined PowerPC Assembly Code:
Putting it all together, the PowerPC assembly code corresponding to the provided hex code is:
li r0, 999
stw r0, 0(r12)
nop
nop
This assembly code sequence loads the immediate value 999 into register r0, stores the contents of r0 into memory at the address stored in r12 (with an offset of 0), and then performs two no-operation instructions.
- ASM INSTRUCTIONS:
- This section is brought to you by ChatGPT! THE ROBOTS ARE TAKING OVER!
The Wii uses a custom PowerPC-based processor known as the "Broadway" CPU. While many instructions are standard PowerPC, some specific variations or additions might exist for console-specific operations or optimizations. Here's a list of PowerPC assembly instructions relevant to the Wii console:
PowerPC ASM instructions for the Wii
# Arithmetic instructions
'add': 7C000034
'addc': 7C0000B4
'adde': 7C0000F4
'addi': 38000000
'addic': 30000000
'addis': 34000000
'addme': 7C000234
'addze': 7C000274
'and': 7C0002F4
'andc': 7C000474
'andi.': 70000000
# Compare instructions
'cmpeq': 7C000634
'cmp': 7C0006B4
'cmpl': 7C0006F4
'cmpli': 28000000
'cntlzw': 7C000734
'cmpwi': 2C000000
'cmplwi': 28000000
# Condition register instructions
'crand': 7C000234
'crandc': 7C0002B4
'creqv': 7C000034
'crnand': 7C0000F4
'crnor': 7C000074
'cror': 7C0002F4
'crorc': 7C000674
'crxor': 7C0000B4
# Divide instructions
'divw': 7C0000B4
'divwu': 7C0001B4
# Extend instructions
'extsb': 7C0001F4
'extsh': 7C000274
# Logical instructions
'eqv': 7C000674
# Load instructions
'lbz': 88000000
'lbzu': 8C000000
'lbzux': 7C0002B4
'lbzx': 80000000
# Store instructions
'stw': 90000000
'stwu': 94000000
'stwux': 7C0002B4
'stwx': 84000000
# System call instructions (specific to Wii development)
'sc': 7C000000
'tw': 7C000000
'td': 7C000000
# Branch instructions
'b': 48000000
'bl': 48000001
'bc': 48000002
'bca': 48000003
'bcl': 48000004
'bcla': 48000005
'bclr': 48000006
'bclrl': 48000007
# NOP instruction
'nop': 60000000
Explanation:
This dictionary includes standard PowerPC instructions (add, and, cmp, lbz, stw, etc.) along with their corresponding hexadecimal opcodes.
Wii-specific Considerations:
Some instructions might be specific to Wii development, particularly related to system calls (sc, tw, td) or optimizations tailored for the console's architecture.
Branch Instructions:
The branch instructions (b, bl, bc, etc.) are crucial for controlling program flow and executing conditional jumps or function calls.
This list provides a foundation for understanding and coding PowerPC assembly language for Wii development, incorporating both general-purpose instructions and those potentially specific to optimizing and interacting with the Wii hardware and software environment.
Hope this helps and if you have any questions I'll do my best to answer them