Welcome, Guest
You have to register before you can post on our site.

Username
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 544
» Latest member: CorvoPSY
» Forum threads: 1,664
» Forum posts: 11,958

Full Statistics

Online Users
There are currently 100 online users.
» 1 Member(s) | 96 Guest(s)
Bing, Facebook, Google

Latest Threads
Make it to 10,000
Forum: General Discussion
Last Post: Fifty
1 hour ago
» Replies: 5,693
» Views: 4,198,982
Custom Kart Working on Do...
Forum: Code Support / Help / Requests
Last Post: CorvoPSY
04-27-2024, 01:14 PM
» Replies: 1
» Views: 60
Boot into TT cup selectio...
Forum: Misc/Other
Last Post: Vega
04-26-2024, 08:27 PM
» Replies: 3
» Views: 2,889
Request: Custom brsars pe...
Forum: Code Support / Help / Requests
Last Post: lschlick
04-25-2024, 05:45 PM
» Replies: 0
» Views: 41
E-mails not working on th...
Forum: General Discussion
Last Post: Fifty
04-19-2024, 04:56 AM
» Replies: 3
» Views: 274
More missing info from Br...
Forum: Coding & Hacking General Discussion
Last Post: Vega
04-15-2024, 10:04 PM
» Replies: 0
» Views: 198
Request: Custom music vol...
Forum: Code Support / Help / Requests
Last Post: lschlick
04-15-2024, 06:13 PM
» Replies: 0
» Views: 199
Request: Additional sound...
Forum: Code Support / Help / Requests
Last Post: _Ro
04-15-2024, 01:50 AM
» Replies: 6
» Views: 245
Mistake in the Broadway M...
Forum: Coding & Hacking General Discussion
Last Post: Vega
04-14-2024, 11:58 PM
» Replies: 0
» Views: 99
Camera Distance Modifier ...
Forum: Visual & Sound Effects
Last Post: vlonebozo
04-13-2024, 11:05 PM
» Replies: 1
» Views: 6,777

 
  About Stack Frames
Posted by: Vega - 03-18-2019, 03:10 AM - Forum: PowerPC Assembly - No Replies

About Stack Frames

For advanced ASM Coders.



Chapter 1. Intro

If you have been working on ASM codes for some time, you may have used one of the following sources below...

Code:
stwu sp, -0x50 (sp) #Push stack, make space for 18 registers
stmw r14, 0x8 (sp)

lmw r14, 0x8 (sp)
addi sp, sp, 0x50 #Pop stack


Code:
stwu sp, -0x80 (sp) #Push stack, make space for 29 registers
stmw r3, 0x8 (sp)

lmw r3, 0x8 (sp)
addi sp, sp, 0x80 #Pop stack


These sources are good methods to get extra registers to utilize for your ASM codes. However, it's better to create a custom stack frame instead of using one of the generic versions above. As you should only use as much stack space as your code requires. This will also involve teaching you how to backup Floating Point Registers to the stack frame if you ever run into a situation that calls for it. You will also learn how to use Stack Frames as space for input and/or output values of Function Calls within your Code(s) instead of relying on the Exception Vector Area.



Chapter 2. Key Instructions; Requirements

You will need to have a basic understanding of Function Calls. Read this tutorial HERE first if you are not familiar with calling functions in your ASM Codes.

You will also need to fully understand some key instructions that you may not have used before, or else none of the other chapters will make much sense.

Those instructions are...
  • stwu
  • stmw
  • stfd
  • lmw
  • lfd

stwu, stmw, and lmw instructions are briefly explained in the Simple ASM Reference Page -> https://mariokartwii.com/showthread.php?tid=863

stwu is explained more in-depth in this tutorial --> https://mariokartwii.com/showthread.php?tid=975
stfd & lfd is explained in this tutorial --> https://mariokartwii.com/showthread.php?tid=1744

The following will provide examples with pics of stmw and lmw if you are not completely familiar with those yet.

Example of stmw:
Code:
stmw r29, 0x00EC (r5)

r5 = 0x80001500
Word of r29 stored as 0x800015EC
Word of r30 stored at 0x800015F0
Word of r31 stored at 0x800015F4

Picture of right before stmw is executed. Instruction is highlighted in green. r5 is outlined in red. r29 thru 31 in blue. Spot where the 3 words will be stored at is outlined in Magenta -

[Image: stack01.png]

Picture of once stmw has executed. Store of r29 shown by red arrow. Store of r30 shown by blue arrow. Store of r31 shown by magenta arrow.

[Image: stack02.png]

Example of lmw:
Code:
lmw r14, 0x1000 (r3)

r3 = 0x80243DD0

r14 thru r31 will be loaded starting at the word located at 0x80244DD0.

Picture of right before lmw is executed. r3 outlined in red. r14 thru 31 outlined blue. Data that will be loaded outlined in magenta.

[Image: stack03.png]

Picture of once lmw has executed. Magenta arrow with the outlines shows the transfer of data from memory to the registers.

[Image: stack04.png]



Chapter 3. Key Elements

It's important to note that the 'pushing/popping' the stack method that you may have been using in your codes is technically not a 'correct' way for making a stack frame. However since C2 (Insert) ASM Gecko Codes are for what is known as "Inline Assembly", the push/pop stack method is perfectly valid. So essentially there's two different ways of creating Stack Frames. The "Inline" method/style (for your everyday Wii ASM Codes) and the Conventional method/style (what you will see most of the Wii Game's function use). The Conventional Method will be covered more in-depth in Chapter 11.

There are 3 key elements when taking about stack frames.
  • r1 aka sp (stack pointer)
  • Stack Frame
  • The Stack

The Stack Pointer (sp) is the register that holds the address which points to the current stack frame. The stack frame is an area of memory that holds values of registers that need to be preserved throughout function call(s). The value in sp is always a static memory address (mem80) and the memory address used in sp must be end in 0 or 8.

The Stack itself is the collection of the current and previous stack frames. When new stack frames are created, the Stack grows toward LOWER memory addresses. So visually in memory, the stack grows up. Thus, sp always points to the very 'top' of the entire Stack.

Since the stack grows toward lower memory addresses, anything before sp's current value in memory is free space to use. This free space is known as the stack's Negative Space (more on this on Chapter 9). Technically, there is a large upper bound limit to this, but it's not a concern for what you will be learning in this tutorial.

Rules of Stack Frames~
  • Stack Frames must have a minimum size of 0x10 bytes.
  • Stack Frame size must be divisible by 0x10. (i.e 0x10, 0x20, 0x30, 0x40 etc etc)
  • Stack Frames has a particular layout that must be followed

Stack Layout using an example stack frame with only one register being backed up (r31), and with sp being the value of 0x80350140:

Mem Address, Offset to Sp, Description
0x80350140, (0x0), Top of Current Stack Frame, previous value of sp (pointer to previous frame) goes here
0x80350144, (0x4), Reserved for Link Register***
0x80350148, (0x8), Padding
0x8035014C, (0xC), r31 (Register storage)
0x80350150, (0x10, Previous Stack Frame

r31 (Register Storage) and Padding can be swapped in position within the the layout if desired. Most stack frames you see created for codes on MarioKartWii.com have the padding after the register storage.

Since the top of the current stack frame (first word value at offset 0x0) always contains the previous/former value of sp, it will contain the value of 0x80350150 in our above example (word value of 0x80350150 is at mem address 0x80350140). Therefore, you can keep following the Stack visually down in memory to see all the previous Stack Frames of the entire Stack. This is known as 'Stack Tracing'.

***This space of 4 bytes (offset 0x4) must be NOT tampered when you create your own custom Stack Frames. More details covered in Chapter 10.

The picture below is the game being paused right after we finished a prologue of a particular function. The size of the Stack Frame is the bare minimum 0x10 bytes and r31 is the only register (excluding the LR) being saved. We can tell the size of this Frame by looking the the stwu instruction's SIMM of -0x10 and simply making that number positive to 0x10. There's other proper methods to determining a Stack Frame's size as reading an stwu instruction is unreliable, but that will be explained later.

The red arrow points to the current stack frame (top of the Stack). The entire Stack Frame is outlined in blue. The backed up r31 is outlined in magenta.

[Image: stack11.png]



Chapter 4. Creating Stack Frames (Inline Style for Gecko ASM Codes)

Let's take another look at the classic 'push/pop' the Stack Method for backing up the Global Variable Registers.

Code:
stwu sp, -0x50 (sp)
stmw r14, 0x8 (sp)

...

lmw r14, 0x8 (sp)
addi sp, sp, 0x50


To create a new stack frame, you first need to backup sp's current value. Based on the size of the new Frame you want to make, you need to store sp's value to a spot at the Stack's Negative Stack Space. You also need to update sp to decrement its value based on what's currently in sp and what the size of your new Frame will be. This can all be accomplished with just one stwu instruction.

Code:
stwu sp, -0x50 (sp) #Backup sp, decrement it to new value based on size of new Frame. Store it to Negative Space also based on the Frame size.

Confused? Let's look at the following pictures.

Right before the stwu instruction gets executed (sp outlined in red pointing to current frame that will become the previous frame once the stwu gets executed)...

[Image: stack05.png]

Here's the picture of once the stwu instruction has executed...

- sp outlined in red pointing to new Frame
- old Frame outlined in blue (notice how the value contained at the address in sp points to where the start of the older Frame is at)

[Image: stack06.png]

Here's a basic formula to know any current Stack Frame's size:
(Sp's old value - Sp's current value) = Size of Stack Frame

Sp's old value is always the first word value of what's in the current Stack Frame.

At this point, the new frame has already been created. The new frame has a size of 0x50 bytes. Now we need an instruction that will store the GVR's to our new frame...

Code:
stmw r14, 0x8 (sp)

This will store r14 thru r31 all onto the stack frame via just one instruction. The store occurs with an offset of 0x8 in reference to sp because at 0x4 is the LR reserved spot (more on the LR reserved spot in Chapter 10)

The following picture shows you what the stack now looks like once the stmw instruction has executed and everything is saved onto the new Frame. Magenta arrow and outlines give you a better visual.

[Image: stack07.png]

Also here's a basic keymap to go along with the above picture.

Mem Address, Offset, Register
80398CF0, 0x8, r14
80398CF4, 0xC, r15
80398CF8, 0x10, r16
80398D00, 0x14, r17
... ...
80398D30, 0x48, r30
80398D34, 0x4C, r31

There was no padding needed at the end. r14 thru r31 fitted into the frame perfectly.



Chapter 5. Destroying Stack Frames (Inline Style for Gecko ASM Codes)

Destroying Frames (also known as popping) is a bit more simpler than creating them. Referring back to Chapter 4, let's look at the following instruction...

Code:
lmw r14, 0x8 (sp) #Restore all the registers from the Frame

Getting our registers (r14 thru r31) is easy to do with the lmw instruction.

Pic of before lmw is executed. You will see I wrote some li instructions above the lmw instruction to edit the GVR's so you can get a better visual for the picture after this one...

[Image: stack08.png]

Pic of after lmw has executed. Magenta arrow and outlines shows the data transfer from memory to the registers...

[Image: stack09.png]

Ok great, we got the Registers back. Now we need sp to be it's previous value so it can point to the older Frame. A simple addi instruction will do the trick.

Code:
addi sp, sp, 0x50 #Pop the current Frame, sp will now point to Previous Frame

Remember when I said the Stack grows toward LOWER addresses? Well obviously a decreasing Stack would recede toward Higher Addresses. This is why we use the addi instruction. It will increase sp's value so we can have it point to the previous Frame. We add sp by 0x50 because the Stack Frame that was most recently created was the size of 0x50 bytes.

Pic of after addi has executed (sp outlined in red which now points to 'old' frame; 'old' frame is now current frame)...

[Image: stack10.png]

And all done! Now that you understand have Frames are Created and Destroyed. Let's go over creating a custom stack frame.



Chapter 6. Custom Frame Sizing

Here's the basic formula of calculating the size you need based on how many GPR's you want to store (FPR's will be covered later).

Number of GPR's x 4 = Sub-Total 1
Sub Total 1 + 8 = Sub Total 2
Round Sub-Total 2 up to be divisible by 0x10.


Let's say we are making a new code and we need 5 extra registers for use. You start with r31 on your count and work towards lower register numbers til you hit the count of 5. Like this..

r31 = 1 free register
r30 = 2 free registers
r29 = 3
r28 = 4
r27 = 5

This will tell us what will be the Destination Register in our stmw instruction. Use the basic formula to calculate the Stack Size for 5 GPR's

5 x 4 = 20 (0x18 hex)
Round 0x18 up to 0x20 so it's divisible by 0x10.

Our minimum required Stack Size is 0x20. We now know what two instructions to use to create our custom Frame.

Code:
stwu sp, -0x20 (sp) #Make new Frame with a size of 0x20
stmw r27, 0x8 (sp) #Backup 5 GPR's to new Frame

And to destory (pop) the frame, these are the two instructions...

Code:
lmw r27, 0x8 (sp) #Restore the 5 GRP's from the Frame
addi sp, sp, 0x20 #Destroy (pop) the Frame



Chapter 7. Storing Floats to a Stack Frame

Storing floats to a stack frame requires special procedures. Without going into endless technical detail, each FPR will take up 16 bytes of memory when storing it to a stack frame since each FPR's value has to be stored twice. Don't worry about attempting to understand what is going on 'under the hood', I will provide an easy to follow template that you can simply 'plug & use'. If you actually want to know what goes on under the hood, read the Paired Single Tutorial HERE after completing this tutorial.

Let's say you wanna just store 2 floating point registers (f1 and f2) to your stack frame. Since each FPR will take 16 bytes, lets run the calculations~

16 x 2 = 32 (0x20 in hex) #2 fprs will take up 32 bytes.

0x20 + 0x8 = 0x28

Round 0x28 up to 0x30 for aligned frame size.


Here's how we would create the stack frame, then store 2 FPRs to it...

Code:
stwu sp, -0x30 (sp)
stfd f1, 0x8 (sp) #Store f1 in double precision mode
psq_st f1, 0x10 (sp) 0, 0 #Store f1 in paired single mode
stfd f2, 0x18 (sp) #Store f2 in double precision mode
psq_st f2, 0x20 (sp) 0, 0 #Store f2 in paired single mode

At this point you are wondering what the hell does 'psq_st' mean, and what the hell is the '0, 0' part of the instructions. Do not worry about it, follow this template for storing an FPR in paired single mode...

Code:
psq_st fD, SIMM (sp), 0, 0

Replace fD will whatever FPR you are utilizing and adjust SIMM accordingly based on where you are storing in reference to the new Frame.

Alright let's say we are at the end of our code, recover the 2 floats...

Code:
psq_l f2, 0x20 (sp), 0, 0
lfd f2, 0x18 (sp)
psq_l f1, 0x10 (sp), 0, 0
lfd f1, 0x8 (sp)
addi sp, sp, 0x30

Follow this template for loading an FPR from the Frame in paired single mode...

Code:
psq_l fD, SIMM (sp) 0, 0

Adjust fD and SIMM accordingly to your needs.

This is a pain in the ass, but it's necessary. Float values could be 'corrupted' if the above special procedures aren't followed.



Chapter 8. Other Uses for Stack Space

Other than storing GPR's and FPR's to a Stack Frame, you can also store items such as input and/or output values from Function Calls that will be called in your ASM Code.

The function known as sprintf takes a string that's in C format and parses it so certain data values are placed into the string. The first argument for sprintf is where the parsed String will be dumped to. A great place for this would be the Stack Frame. No need to take up space in the Exception Vector Area.

Example:
Code:
addi r3, sp, 8 #Make the parsed string dump to the very start of our Stack Frame. Let's pretend all other sprintf args are already set in their respective registers.
lis r12, 0x8001 #PAL sprintf function address
ori r12, r12, 0x1A2C
mtctr r12
bctrl #Call it

For more details about sprintf, view this thread HERE.

Once the function has completed and no errors have occurred, the output for sprintf will be at the start of the Frame. You will need to know how much space in your Stack Frame to allocate for this. Be sure to make a Stack Frame that will have enough space!



Chapter 9. Negative Stack Space Tricks

I've mentioned earlier that the negative area of the Stack Pointer is safe to use. If your code doesn't include any function calls, you can simply store register values to the negative area w/o creating a new Stack Frame. This is because prologues of Function Calls will create new frames, and whatever is in the negative Stack area will be overwritten.

Example where you need 3 free registers, so you backup r29, r30, & r31~

Code:
stwm r29, -0xC (sp) #r29 stores at -0xC in reference to sp, r30 at -0x8, r31 at -0x4

...

lmw r29, -0xC (sp)

Another handy trick for using negative stack space is for Float to Integer conversions.

Let's say you have a float in f1, you wanna convert it to an integer back into f1. Then finally have that integer value loaded into r10. Here's how you can do that via Negative Stack Space...

Code:
fctiw f1, f1 #Convert float to integer, standard rounding
stfd f1, -0x8 (sp) #Store result to negative space, integer result is in lower 32 bits of the double-word
lwz r10, -0x4 (sp) #Load integer into r10



Chapter 10. Explaining the purpose of the reserved LR Spot

As mentioned earlier in Chapter 3 in regards to the Stack Layout, you cannot use the word spot that is at sp+0x4. This is because when another function calls gets executed, its prologue includes two instructions that will backup the LR into r0 then store r0 onto the LR reserved spot of the Previous Frame!

Confused?

Let's look at a picture we have looked at before. The pic that shows us right after completing a prologue of a function in the game. Where the stack size was the bare minimum 0x10.

[Image: stack12.png]

r1 (sp) in the registers tab is outlined in Red. The value in r1 points to the start of the new frame. In the Memory Viewer, you can see the start of the new frame (what r1 points to) outlined is also outline in Red.

In the registers tab, the Link Register is outlined in blue. You can see in the Code View, the instructions that place LR's value in r0 then store it to the LR reserved spot of the PREVIOUS/OLD frame is also outlined in blue. The LR reserved spot itself (of the previous/old frame) in the Memory Viewer is outlined in blue as well.

As you can see the saved LR is always placed in the LR reserve spot of the previous/old frame. Now that you understand the LR reserved spot, we can cover how to push and pop the Stack via the Conventional Method.



Chapter 11. Creating + Destroying Stack Frames (Conventional Method)

You could, as an option, push and pop the Stack via the conventional method, instead of the "Inline" method. In reality, it's never really needed for Gecko ASM Codes, because 99% of the time r11 and r12 are safe to write to. If you need to backup something such as the LR, you would just write it to r12 before the initial stack push like so...

Code:
#Make Stack to backup 2 registers, also need to backup LR
mflr r12
stwu sp, -0x10 (sp)
stmw r30, 0x8 (sp)

...

#Pop it
lmw r30, 0x8 (sp)
addi sp, sp, 0x10
mtlr r12

The reason why this "hacky" method of saving LR (and other registers such as r0 and CTR) is preferred is that it can reduce the size of the Stack and it reduces the amount of instructions required. However, if you want to still use the conventional way, here's how...

Conventional Push Method (aka Prologue of a function)~
Code:
#Make Stack to backup 2 registers, use conventional method to backup LR
stwu sp, -0x10 (sp) #Make new frame
mflr r0 #Temp place LR into r0; r0 in normal operation is used as a scrap register
stw r0, 0x0014 (sp) #Store LR to its reserved spot in previous Frame
stmw r30, 0x8 (sp) #Backup 2 registers

Conventional Pop Method (aka Epilogue of a function)~
Code:
#Pop it
lmw r30, 0x8 (sp) #Recover registers
lwz r0, 0x0014 (sp) #Temp place old LR into r0
mtlr r0 #Recover old LR
addi sp, sp, 0x10 #Destroy frame, make sp point to old frame

Here's an easy formula/guide to always remember the proper 'offset' to use when storing the LR.

1. Take the offset value used in the stwu and make it positive (example: -0x10 to 0x10)
2. Now simply add 4 (0x10 + 4 = 0x14)

Super simple and obviously you would use that calculated offset when retrieving the LR during the pop.

As you can see this takes more instructions to execute compared to the Inline/Hacky method.

Happy coding!

Print this item

  Using Mem81 to Auto-Clear Data for ASM Codes (MKWii only)
Posted by: Vega - 03-18-2019, 02:45 AM - Forum: PowerPC Assembly - Replies (1)

Using Mem81 to Auto-Clear Data for ASM Codes (MKWii only)

NOTE: This is an MKWii specific 'feature', this most likely won't work for other Wii games.
NOTE: For beginner ASM Coders that have already been utilizing the Exception Vector Area in previous codes.


Let's say you have an ASM code that originally stores data/values to the Exception Vector Area. You wanted these values to clear after every race. So you write another ASM code (that occurs only in between races) to zero/null out all the values.

Seems pretty silly to write another whole ASM code just to clear values. Instead of storing your data/values to the Exception Vector Area, you store them to Mem81. Mem81 auto-clears after every race/battle. The only time is doesn't auto clear is pressing restart in TT mode. I don't know the entire exact allowable region of Mem81 but here is a LARGE chunk used many various codes over time and I have seen no issues with any of those codes' functionality.

0x81400000 thru 0x81701000

As you can see this is a very large region of memory to have at your expense. And there you go, a great place to store values that need to be cleared per race. Happy coding!

Print this item

  Using the Exception Vector Area in ASM Codes
Posted by: Vega - 03-18-2019, 02:31 AM - Forum: PowerPC Assembly - No Replies

Using the Exception Vector Area in ASM Codes

If you have started making ASM Codes recently, you will eventually hit a point where you need to store values during one ASM code, to later utilize said values in another ASM Code. This would require you to use some sort of store-type instructions in the 1st ASM to store the desired data to a spot in memory. Then in the 2nd ASM, you would use load-type instructions to load that desired data from memory.

Here's a super basic diagram~

[Image: evaintrodiagram.png]

Obviously you wouldn't want to store the desired data in Dynamic memory. You also cannot just choose a random place in Static Memory, even if that random spot is full of bytes of zeroes.

For every Wii game there is a region of memory where instructions for a variety of crash-recovery subroutines are located at. This region of memory is called the Exception Vector Area (or just EVA). The crash-recovery subroutines have unused spaces of memory in between each other. Those unused spaces are what you can safely use to store data at to later retrieve it. The EVA is universal (same location in memory) for every Wii game.

Here are the address ranges....

NOTE! You may find these ranges to not be accurate if you are viewing the Game's memory from Dolphin. However, on the Wii Console, these are the correct ranges which are tighter (less room to work with) than what appears on Dolphin. These were taken when running a CLEAN MKW ISO (no patches). Various patching could effect these ranges.

Safe ranges to use:
0x800001B0 thru 0x800001FF
0x800002B0 thru 0x800002FF
0x800003B0 thru 0x800003FF
0x800004B0 thru 0x800004FF
0x800005B0 thru 0x800005FF
0x800006B0 thru 0x800006FF
0x800007B0 thru 0x800007FF
0x800008B0 thru 0x800008FF
0x800009B0 thru 0x80000BFF
0x80000CB0 thru 0x80000CFF
0x80000DB0 thru 0x80000EFF
0x80000FB0 thru 0x80000FFF
0x800011C0 thru 0x800012FF
0x800013B0 thru 0x800013FF
0x800014B0 thru 0x800016FF
0x800017B0 thru 0x800017FF


Keep in mind that many other/older ASM codes utilize the 0x800014B0 thru 0x800016FF range. So it is best to pick a different area to use, as you don't want to end up using the same exact location in memory as another code.

Here's a simple code showing how to utilize the Exception Vector Area...

https://mariokartwii.com/showthread.php?tid=889


Code:
NTSC-U
C27AC3C0 00000002
3D808000 992C164F
2C09000C 00000000
C27AB704 00000005
3D808000 896C164F
2C0B000X 40A20010
2C19000Y 40A20008
386000WW 90770020
60000000 00000000

X = In-Race Room Size
Y = Position
WW = Item


The In-Race Room Size & Position Based Shared Item Code is just like an old school Shared Item Code but it is only designed to execute when the player is in a specific position AND the in-race room size is a specific amount. If you are not familiar with what the original Shared Item code is. It's basically a Force Next Item Code. In the original code, there's only one value for the user to fill out (Item). You choose which Item you always want to get when picking up a box.

The 1st ASM has a register that contains the in-race room size. The 2nd ASM uses the same address as the Shared Item but has extra instructions regarding the EVA, the player's position, and some basic comparison+branches.

We are not going to cover much about the Position part as that information is already available in a register during the execute of the Shared Item Code address. What's more important is the in-race room size. As that information is not available during the execution of the Shared Item Code address. Thus an entirely other ASM code had to be created.

We'll go over the sources of the code with the X value as 4, Y value as 1, and WW value as 03 (Fib).

Here's the 1st Source/ASM that deals with the in-race room size.

Code:
lis r12, 0x8000 #Set the upper 16 bits of the EVA
stb r9, 0x164F (r12) #Store the in-race room size to the EVA
cmpwi r9, 0xC #Default instruction

The 1st source is very simple. A spare register was used to make the value of 0x80000000. Then r9's value (which always contain the updated in-race room size), is stored as a byte to a spot in the EVA (0x8000164F). Finally the default instruction is executed. The address of this ASM gets called at the beginning of any race and gets called again whenever the in-race room size is changed during the race. Thus the in-race room size byte value that's in the EVA will always get updated whenever the ASM's address is executed due to an update in the in-race room size.

So the 1st source is executed, now there is some byte data at the EVA. Let's look at the 2nd source now...

Code:
lis r12, 0x8000 #Set the Upper 16 bits of the EVA
lbz r11, 0x164F (r12) #Load in-race room size value from EVA
cmpwi r11, 0x4 #Compare In-Race Room size to the X User setting (4)
bne+ dont_execute #If in-race room size is NOT equal to 4, do not execute the Shared Item

cmpwi r25, 1 #If in-race room size value is 4, we now check the Y User setting (1) in comparison to the player's actual current position
bne+ dont_execute #If player's position isn't equal to 1, do not execute the Shared Item

li r3, 0x3 #Both checks have been met, make the player receive a Fib from the Box

dont_execute:
stw r3, 0x0020 (r23) #Default instruction

The 2nd source/ASM is a bit more complex. So first, that in-race room size byte at the EVA is loaded and is placed into r11 (spare register; free to use). Then what's in r11 is compared to the value of 4. If they are not equal, it means the in-race room size isn't 4, so the rest of the code is skipped and only the default instruction is executed afterwards.

If r11 was 4, then a second check is preformed. Whenever the Shared Item code address is executed, r25 always contains the player's position and it is always updated...

Helpful Tip: When making your own new code(s), be sure to check other register values that are NOT part of the Default Instruction to see if you can find any extra information that could be useful for making said new code(s).

If r25 (player's current positon) is not equal to 1, then the forcing of the Fib Item (li r3, 0x3) is skipped, thus the Default instruction gets executed and the code has completed.

If r25 is equal to 1, then both checks are true, r3 is set to 3 (this will now force a Fib), the default instruction is executed afterwards and the code has completed with a Fib being activated.

Final NOTE: You may have noticed in the 2nd source/ASM that two branches used the same label name thus both of the branches had the same 'landing spot' (at the default instruction). This is perfectly fine and causes no issues. Not every branch 'route' has to have a different 'landing spot'. Don't forget that you can do this with as many branches as you want. Let's pretend the code had 7 total checks (instead of 2), you can have all 7 branches land at the same spot in the source (if that is what you want of course).

Happy coding!



For anyone who's interested, here are the Vectors themselves~

Note: These vectors are executed physically, so addresses are displayed in physical value

0x00000100 - System Reset
0x00000200 - Machine Check
0x00000300 - Data Storage Interrupt
0x00000400 - Instruction Storage Interrupt
0x00000500 - External Interrupt
0x00000600 - Alignment
0x00000700 - Program
0x00000800 - Floating Point Unavailable
0x00000900 - Decrementer
0x00000C00 - System Call
0x00000D00 - Trace
0x00000F00 - Performance Monitor
0x00001000 - ???*
0x00001300 - Instruction Address Breakpoint
0x00001400 - System Management
0x00001700 - Thermal Interrupt**

*This does not appear to be a normal vector. For starters the beginning instructions are not utilizing the SPRG's. Secondly the end of the vector doesn't conclude with a rfi instruction. It ends with a blr, and then there's a few more instructions afterwards which ends in a 'mtctr r31'. There are 4 famous RAM Dumps (one for each region) that have been on the net for ages. This custom vector is not present on the PAL and JPN dumps. All Dumps had the Gecko Handler equipped as an fyi. If you do a RAM Dump with my Dump Code on the Wii console, you will also see this odd vector.

**A thermal interrupt is present but it is not used. In fact, if you read the Broadway Manual, there's no mention of a Thermal Interrupt Vector. Probably present due to incorrect snippets of code during the boot process of the Wii Menu by the Nintendo Devs.

Another note: 0x00000A00 is normally used for by other PPC systems for 'Critical Interrupt', but it is not present/used.

Print this item

  Dump All Opponents' IP Address & Important USER Record Info to NAND [Vega]
Posted by: Vega - 03-08-2019, 09:43 PM - Forum: Online Non-Item - No Replies

Dump All Opponents' IP Address & Important USER Record Info to NAND [Vega]

NOTE: Does NOT work on Wiimmfi (due to their security patches). Yes, I have a version that works on Wiimmfi, but I won't be releasing it. This is because that version will probably get patched within 24 hours if it were released, and I don't want to be in a 'battle' going back and forth w/ the Wiimmfi staff.

This code will create a new file on your NAND called "openme" within the /shared2 directory. The openme file will contain the following info from all opponents (your info will NOT be included)...

Mii Name
Client ID
Wii ID
Friend Code
Slot in Last Race
IPv4 Address

The openme file will contain info from the last race of when it was updated. The file gets updated at the start of each race, replacing the previous race info with the updated info. If you have the info you want after the race starts and don't want the file updated again next race, leave the WW/Room once the current race is over.

How to extract the openme file from your NAND:

You can use the WiiXplorer app or the FSToolBox app. I personally prefer WiiXplorer. You can find either of those HBC apps via a quick Google Search. You will need some experience with HBC and using HBC apps as the following steps will not be a full 'baby-you-step-by-step' guide.

Mini Guide (WiiXplorer)
1. Launch WiiXplorer, go to Settings, then Boot Settings.
2. Turn on NAND Access/Permissions (must be done every time you boot the app)
3. Go to NAND root, go into the shared2 folder. Copy paste the openme file anywhere to your SD/USB.
4. Put SD/USB into computer. Use any Hex Editor to view the file (I recommend HxD). Congratz

openme Overall Player Address Values
0x00 -p1 (slot 0)
0x40 -p2 (slot 1, etc etc)
0x80 - p3
0xC0 - p4
0x100 - p5
0x140 - p6
0x180 - p7
0x1C0 - p8
0x200 - p9
0x240 - p9
0x280 - p10
0x2C0 - p11
0x300 - p12

openme Specific Player Address Offsets (add the players Overall Address value to this value to find it on the Hex Editor. Example you want to see Player 5's FC. Add 0x100 plus 0x20. At address 0x120 on the file will be the FC value of Player 5):
0x0 Mii Name (5 words)
0x14 Client ID (word)
0x18 Wii ID (double word)
0x20 FC (double word)
0x28 Player slot (byte)
0x2C IPv4 Address (word)

Note about IP slotting: If there are guests in the room, it will mess up where the IP addresses are slotted. Not much I can do about this (without making the code way longer than it already is) because the game doesn't repeat a persons' IP in RAM if that person has a guest.

For example--
If there are 6 players in the room and 2 of those have guests, then there are only 4 total IP addresses. So let's say we have these 4 IP Addresses (hex) 
11223344 (slot 0 w/ guest slot 1)
99887755 (slot 2)
10101010 (slot 3 w/ guest slot 4)
22224444 (slot 5)

This is how those IP Addresses would be listed on openme
slot 0 ip's 11223344
slot 1 ip's 99887755
slot 2 ip's 10101010
slot 3 ip's 22224444
slot 4 ip's none (all zeros)
slot 5 ip's none (all zeros)

Instead of making the code way longer than what it is, I decided to leave this up to the end user to manually adjust if they dump the info of a WW that has guests.

Final Important NOTE: This code makes use of memory addresses 0x800015A0 thru 0x800015D3, and 0x81490000 thru 0x81490003. Make sure no other codes you have on, are using those addresses!!!

NTSC-U
C20DB29C 00000003
9B440014 3984003C
3D608000 918B15D0
60000000 00000000
C261E0C8 00000003
7C630214 1C910004
3C848000 906415A0
60000000 00000000
C27AC3BC 00000031
3D808149 816C0000
2C0B0000 40A20174
908C0000 7C0B0378
7D8802A6 9421FF80
BC610008 38600340
38800020 80ADA358
80A50024 7CBA2B78
3D808022 618C9490
7D8803A6 4E800021
7C7B1B78 3F208000
632C159C 39C0000C
856C0004 2C0B0000
40A20011 35CEFFFF
4082FFF0 48000054
7D4802A6 558F063E
39EFFF60 55EFF0BE
1E0F0040 7E3B8214
91F10028 825915D0
1E0F0030 7E50902E
9251002C 392B00D2
7E69A4AA 7E71A5AA
83EB00EC 93F10014
BB8B0168 BF910018
7D4803A6 4E800020
3FA08016 48000015
2F736861 72656432
2F6F7065 6E6D6500
7C6802A6 7C7E1B78
38800000 38A00003
7CA62B78 7CA72B78
63BCABD4 7F8803A6
4E800021 2C03FF97
41A2000C 2C030000
40820050 7FC3F378
38800002 63BCADBC
7F8803A6 4E800021
2C030000 41800034
7C7F1B78 7F64DB78
38A00340 63BCB220
7F8803A6 4E800021
2C030340 40820014
7FE3FB78 63BCB2E4
7F8803A6 4E800021
7F63DB78 7F44D378
3D808022 618C9800
7D8803A6 4E800021
B8610008 38210080
7D8803A6 7D605B78
7C0903A6 00000000

PAL
C20DB33C 00000003
9B440014 3984003C
3D608000 918B15D0
60000000 00000000
C26513DC 00000003
7C630214 1C910004
3C848000 906415A0
60000000 00000000
C27BAE1C 00000031
3D808149 816C0000
2C0B0000 40A20174
908C0000 7C0B0378
7D8802A6 9421FF80
BC610008 38600340
38800020 80ADA360
80A50024 7CBA2B78
3D808022 618C9814
7D8803A6 4E800021
7C7B1B78 3F208000
632C159C 39C0000C
856C0004 2C0B0000
40A20011 35CEFFFF
4082FFF0 48000054
7D4802A6 558F063E
39EFFF60 55EFF0BE
1E0F0040 7E3B8214
91F10028 825915D0
1E0F0030 7E50902E
9251002C 392B00D2
7E69A4AA 7E71A5AA
83EB00EC 93F10014
BB8B0168 BF910018
7D4803A6 4E800020
3FA08016 48000015
2F736861 72656432
2F6F7065 6E6D6500
7C6802A6 7C7E1B78
38800000 38A00003
7CA62B78 7CA72B78
63BCAC74 7F8803A6
4E800021 2C03FF97
41A2000C 2C030000
40820050 7FC3F378
38800002 63BCAE5C
7F8803A6 4E800021
2C030000 41800034
7C7F1B78 7F64DB78
38A00340 63BCB2C0
7F8803A6 4E800021
2C030340 40820014
7FE3FB78 63BCB384
7F8803A6 4E800021
7F63DB78 7F44D378
3D808022 618C9B84
7D8803A6 4E800021
B8610008 38210080
7D8803A6 7D605B78
7C0903A6 00000000

NTSC-J
C20DB25C 00000003
9B440014 3984003C
3D608000 918B15D0
60000000 00000000
C2650A48 00000003
7C630214 1C910004
3C848000 906415A0
60000000 00000000
C27BA488 00000031
3D808149 816C0000
2C0B0000 40A20174
908C0000 7C0B0378
7D8802A6 9421FF80
BC610008 38600340
38800020 80ADA360
80A50024 7CBA2B78
3D808022 618C9734
7D8803A6 4E800021
7C7B1B78 3F208000
632C159C 39C0000C
856C0004 2C0B0000
40A20011 35CEFFFF
4082FFF0 48000054
7D4802A6 558F063E
39EFFF60 55EFF0BE
1E0F0040 7E3B8214
91F10028 825915D0
1E0F0030 7E50902E
9251002C 392B00D2
7E69A4AA 7E71A5AA
83EB00EC 93F10014
BB8B0168 BF910018
7D4803A6 4E800020
3FA08016 48000015
2F736861 72656432
2F6F7065 6E6D6500
7C6802A6 7C7E1B78
38800000 38A00003
7CA62B78 7CA72B78
63BCAB94 7F8803A6
4E800021 2C03FF97
41A2000C 2C030000
40820050 7FC3F378
38800002 63BCAD7C
7F8803A6 4E800021
2C030000 41800034
7C7F1B78 7F64DB78
38A00340 63BCB1E0
7F8803A6 4E800021
2C030340 40820014
7FE3FB78 63BCB2A4
7F8803A6 4E800021
7F63DB78 7F44D378
3D808022 618C9AA4
7D8803A6 4E800021
B8610008 38210080
7D8803A6 7D605B78
7C0903A6 00000000

NTSC-K
C20DB39C 00000003
9B440014 3984003C
3D608000 918B15D0
60000000 00000000
C263F6F4 00000003
7C630214 1C910004
3C848000 906415A0
60000000 00000000
C27A91DC 00000031
3D808149 816C0000
2C0B0000 40A20174
908C0000 7C0B0378
7D8802A6 9421FF80
BC610008 38600340
38800020 80ADA380
80A50024 7CBA2B78
3D808022 618C9B88
7D8803A6 4E800021
7C7B1B78 3F208000
632C159C 39C0000C
856C0004 2C0B0000
40A20011 35CEFFFF
4082FFF0 48000054
7D4802A6 558F063E
39EFFF60 55EFF0BE
1E0F0040 7E3B8214
91F10028 825915D0
1E0F0030 7E50902E
9251002C 392B00D2
7E69A4AA 7E71A5AA
83EB00EC 93F10014
BB8B0168 BF910018
7D4803A6 4E800020
3FA08016 48000015
2F736861 72656432
2F6F7065 6E6D6500
7C6802A6 7C7E1B78
38800000 38A00003
7CA62B78 7CA72B78
63BCAD10 7F8803A6
4E800021 2C03FF97
41A2000C 2C030000
40820050 7FC3F378
38800002 63BCAEF8
7F8803A6 4E800021
2C030000 41800034
7C7F1B78 7F64DB78
38A00340 63BCB35C
7F8803A6 4E800021
2C030340 40820014
7FE3FB78 63BCB420
7F8803A6 4E800021
7F63DB78 7F44D378
3D808022 618C9EF8
7D8803A6 4E800021
B8610008 38210080
7D8803A6 7D605B78
7C0903A6 00000000



List of Sources:

Source for IP Dynamic Word Location ('Pointer') Storage (1st ASM):

stb r26, 0x0014 (r4) #Default Instruction
addi r12, r4, 0x3C #Add 0x3C to r4. Store result to r12. r12's memory location is now exactly at player slot 0's IP
lis r11, 0x8000 #Set 1st half address of where in memory we are storing the word of r12 to
stw r12, 0x15D0 (r11) #Store the word of r12 to 0x800015D0

================================================================

Source for USER Record Pointers Storage (2nd ASM):

#r4 safe for use, gets written to by following address instruction#
#this code address never gets called for your slot#

add r3, r3, r0 #Default Instruction; r3 is player USER pointer
mulli r4, r17, 0x4 #r17 is player slot value
addis r4, r4, 0x8000
stw r3, 0x15A0 (r4)

================================================================

Source of NAND Writes (3rd ASM):

#~~~~~~~~~~~~~~~~#
# START ASSEMBLY #
#~~~~~~~~~~~~~~~~#

#

#~~~~~~~~~~~~~~~~~~~~#
# Macros & Variables #
#~~~~~~~~~~~~~~~~~~~~#

.macro call_link address
    lis r12, \address@h
    ori r12, r12, \address@l
    mtlr r12
    blrl
.endm

.macro call_isfs address
    ori r28, r29, \address@l
    mtlr r28
    blrl
.endm

.macro push_stack #No need to backup CTR as it gets written to by default instruction at end of code
    mr r11, r0
    mflr r12
    stwu r1, -0x80 (r1)
    stmw r3, 0x8 (r1)
.endm

.macro pop_stack
    lmw r3, 0x8 (r1)
    addi r1, r1, 0x80
    mtlr r12
    mr r0, r11
.endm

.macro default_instruction
    mtctr r0
.endm

.set region, '' #Fill in E, P, J, or K within the quotes for your region when Compiling! Lowercase letters can also be used.

.if     (region == 'E' || region == 'e') # RMCE
    .set ISFS_CreateFile, 0xABD4
    .set ISFS_Open, 0xADBC
    .set ISFS_Write, 0xB220
    .set ISFS_Close, 0xB2E4
    .set Egg_Alloc, 0x80229490
    .set Egg_Free, 0x80229800
.elseif (region == 'P' || region == 'p') # RMCP
    .set ISFS_CreateFile, 0xAC74
    .set ISFS_Open, 0xAE5C
    .set ISFS_Write, 0xB2C0
    .set ISFS_Close, 0xB384
    .set Egg_Alloc, 0x80229814
    .set Egg_Free, 0x80229B84
.elseif (region == 'J' || region == 'j') # RMCJ
    .set ISFS_CreateFile, 0xAB94
    .set ISFS_Open, 0xAD7C
    .set ISFS_Write, 0xB1E0
    .set ISFS_Close, 0xB2A4
    .set Egg_Alloc, 0x80229734
    .set Egg_Free, 0x80229AA4
.elseif (region == 'K' || region == 'k') # RMCK
    .set ISFS_CreateFile, 0xAD10
    .set ISFS_Open, 0xAEF8
    .set ISFS_Write, 0xB35C
    .set ISFS_Close, 0xB420
    .set Egg_Alloc, 0x80229B88
    .set Egg_Free, 0x80229EF8
.else # Invalid Region
        .abort
.endif

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#        Memory Address & Register Notes      #
#   0x800015A0 = Slot 0 User Pointer (Word)   #
#         0x800015A4 = Slot 1, etc etc        #
#          0x800015CC = Slot 11 (0xB)         #
# 0x800015D0 = Pointer to IP Address Mem Area #
#          0x81490000 = Status Word           #
# r25 = Exeception Vector First Half Address  #
#    r26 = System Heap Calc Address Pointer   #
#          r27 = Heap Address Pointer         #
#           r28 = Part of ISFS Macro          #
#          r29 = 0x8016 for ISFS Calls        #
#       r30 = File Path Address Pointer       #
#             r31 = File Descriptor           #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

#~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#     Status Word Check:    #
#   We don't want the code  #
# to execute more than once #
#  per race. Hence why this #
#          is done.         #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~#

lis r12, 0x8149
lwz r11, 0x0 (r12)
cmpwi r11, 0x0
bne+ dont_execute

#~~~~~~~~~~~~~~~~~~~~#
# Update Status Word #
#~~~~~~~~~~~~~~~~~~~~#

stw r4, 0x0 (r12) #We need anything not zero for storage, r4 always has a value. Store it

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Start Register Safety/Backup #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

push_stack

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#          EGG::Heap:alloc         #
#        r3 = Size of Heap         #
#          r4 = Alignment          #
#      r5 = System Heap Calc       #
# Return r3 = Heap Address Pointer #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

li r3, 0x340
li r4, 0x20 #32-bit

.if     (region == 'E' || region == 'e')
        lwz r5, -0x5CA8(r13)
.elseif (region == 'P' || region == 'p')
        lwz r5, -0x5CA0(r13)
.elseif (region == 'J' || region == 'j')
        lwz r5, -0x5CA0(r13)
.elseif (region == 'K' || region == 'k')
        lwz r5, -0x5C80(r13)
.endif 

lwz r5, 0x24 (r5)
mr r26, r5 #Backup System Heap Calc Address

call_link Egg_Alloc

mr r27, r3 #Backup Heap Address Pointer

#~~~~~~~~~~~~~~~~~#
# Pre-Loop Config #
#~~~~~~~~~~~~~~~~~#

lis r25, 0x8000
ori r12, r25, 0x159C #Set r12 to 0x8000159C
li r14, 0xC

#~~~~~~#
# Loop #
#~~~~~~#

the_loop:
lwzu r11, 0x4 (r12) #r11 contains current Player's USER Record Pointer
cmpwi r11, 0x0 #Your own slot will never be available for loading (zero)
bnel+ sub_routine
subic. r14, r14, 1
bne+ the_loop
b loop_done

#~~~~~~~~~~~~#
# Subroutine #
#~~~~~~~~~~~~#

sub_routine:
mflr r10 #Backup LR due to later use of memcpy

#~~~~~~~~~~~~~~~~~~~~~~~~#
# Player Slot Value Calc #
#~~~~~~~~~~~~~~~~~~~~~~~~#

clrlwi r15, r12, 24 #Clear out first 3 bytes (24bits) of r12's value, r12 always updated due to the loop.
addi r15, r15, -0xA0 #Subtract 0xA0 from leftover value
srwi r15, r15, 2 #Shift the word by 2 bits. Final result is the slot value. This is the same as dividing r15 by 0x4.

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Calculate Player's Exact Address in the Heap #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mulli r16, r15, 0x40
add r17, r27, r16

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Store Player's Slot Value to Heap #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

stw r15, 0x28 (r17)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Player's IP Address Calculation & Store to Heap #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

lwz r18, 0x15D0 (r25) #Grab IP Address Slot 0 Address Pointer from 0x800015D0
mulli r16, r15, 0x30 #Each Slot's IP Address is gapped by 0x30 in Memory
lwzx r18, r16, r18
stw r18, 0x2C (r17)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Load & Store Player's Mii Name #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

addi r9, r11, 0xD2 #Set up r4 as the loading address for the following lswi instruction
lswi r19, r9, 20 #Load the 20 byte string at address of r9 into starting register 19 (r19 thru r23 are written)
stswi r19, r17, 20 #Store the 20 byte string of r19 thru r23 to address of r17 (player's beginning heap spot)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Load & Store Player's Client ID #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

lwz r31, 0xEC (r11)
stw r31, 0x14 (r17)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Load & Store Player's Wii ID + FC #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

lmw r28, 0x168 (r11)
stmw r28, 0x18 (r17)

#~~~~~~~~~~~~~~~~#
# Return to Loop #
#~~~~~~~~~~~~~~~~#

mtlr r10
blr

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Setup 1st Half Address of ISFS Functions #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

loop_done:
lis r29, 0x8016

#~~~~~~~~~~~~~~~~~~~~~~~~#
#     ISFS_CreateFile    #
# r3 = File Path Address #
#   r4 = u8 attributes   #
# r5 = Owner permission  #
# r6 = Group permission  #
# r7 = Other permission  #
#~~~~~~~~~~~~~~~~~~~~~~~~#

bl create_file

.llong 0x2F73686172656432 #String for "/shared2/openme"
.llong 0x2F6F70656E6D6500

create_file:
mflr r3
mr r30, r3 #Backup File Path Address

li r4, 0x0
li r5, 0x3
mr r6, r5
mr r7, r5

call_isfs ISFS_CreateFile

cmpwi r3, -105
beq+ file_alreadymade
cmpwi r3, 0x0
bne- free_egg

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#           ISFS_Open           #
#     r3 = File Path Address    #
# r4 = 0x2 for Write Permission #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

file_alreadymade:
mr r3, r30
li r4, 0x2

call_isfs ISFS_Open

cmpwi r3, 0x0
blt- free_egg

mr r31, r3 #Backup file descriptor

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#                     ISFS_Write                      #
#                r3 = File descriptor                 #
# r4 = Address that Points to String of Data to Write #
#    r5 = Amount of Bytes to Write from the String    #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mr r4, r27
li r5, 0x340

call_isfs ISFS_Write

cmpwi r3, 0x340
bne- free_egg

#~~~~~~~~~~~~~~~~~~~~~~#
#      ISFS_Close      #
# r3 = File descriptor #
#~~~~~~~~~~~~~~~~~~~~~~#

mr r3, r31

call_isfs ISFS_Close

#~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#      EGG::Heap::free      #
# r3 = Heap Address Pointer #
#   r4 = System Heap Calc   #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~#

free_egg:
mr r3, r27
mr r4, r26

call_link Egg_Free

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# End Register Safety/Backup; Default Instruction #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

pop_stack

dont_execute:
default_instruction

#

#~~~~~~~~~~~~~~#
# END ASSEMBLY #
#~~~~~~~~~~~~~~#



Code creator: Vega

Code credits: Megazig (ISFS Functions), Star (address founder for 2nd ASM), RiiDefi (EGG Functions)

Print this item

  Performance Bar [MrBean]
Posted by: Star - 03-04-2019, 03:59 PM - Forum: Misc/Other - No Replies

Performance Bar [MrBean]

(NTSC-U)
C20095CC 00000006
81950000 7EA3AB78
818C0018 7D8903A6
4E800421 81830000
818C0008 7D8903A6
4E800421 81950000
60000000 00000000
C20095EC 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0010
7D8903A6 4E800421
60000000 00000000
C200964C 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0014
7D8903A6 4E800421
60000000 00000000
C2009764 00000007
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
39800001 9983010A
81830000 818C000C
7D8903A6 4E800421
60000000 00000000

(PAL)
C200960C 00000006
81950000 7EA3AB78
818C0018 7D8903A6
4E800421 81830000
818C0008 7D8903A6
4E800421 81950000
60000000 00000000
C200962C 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0010
7D8903A6 4E800421
60000000 00000000
C200968C 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0014
7D8903A6 4E800421
60000000 00000000
C20097A4 00000007
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
39800001 9983010A
81830000 818C000C
7D8903A6 4E800421
60000000 00000000

(NTSC-J)
C2009568 00000006
81950000 7EA3AB78
818C0018 7D8903A6
4E800421 81830000
818C0008 7D8903A6
4E800421 81950000
60000000 00000000
C2009588 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0010
7D8903A6 4E800421
60000000 00000000
C20095E8 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0014
7D8903A6 4E800421
60000000 00000000
C2009700 00000007
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
39800001 9983010A
81830000 818C000C
7D8903A6 4E800421
60000000 00000000

(NTSC-K)
C2009714 00000006
81950000 7EA3AB78
818C0018 7D8903A6
4E800421 81830000
818C0008 7D8903A6
4E800421 81950000
60000000 00000000
C2009734 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0010
7D8903A6 4E800421
60000000 00000000
C2009794 00000006
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
81830000 818C0014
7D8903A6 4E800421
60000000 00000000
C20098AC 00000007
4E800421 81950000
7EA3AB78 818C0018
7D8903A6 4E800421
39800001 9983010A
81830000 818C000C
7D8903A6 4E800421
60000000 00000000

Code Creator: MrBean

Print this item

  Using Assembler Directives
Posted by: Vega - 03-03-2019, 07:53 PM - Forum: PowerPC Assembly - No Replies

Using Assembler Directives in your Source



Chapter 1: Intro

Gecko Code Assemblers all have a feature called Assembler Directives. Assembler Directives are various instructions (these are NOT actual PPC Instructions!!!) that tell the Assembler about any symbols, macros, statements, etc that are in your Source and how to apply them to help assemble your Code. If you have been following my "Go From Noobs to ASM Coder" index, you will have already learned about some Assembler Directives known as "Pseudo Ops" in the "BL Trick" thread.

When your ASM Codes are becoming too large/complex, it may be time to start using Directives. You may have a chunk of code that is present multiple times in your source. Why write it out multiple times when you can just write it out once and have it applied to multiple locations? Not only that, are you running into situations of having to memorize a specific numerical value for something that is commonly known by name? Directives allow you to use Names to represent any numerical value.



Chapter 2: Setting Symbols

You can direct specific names to any numerical value you want. This is done via the SET directive. Anything that uses the SET directive is known as a Symbol.

Format~
.set name, expression

name = The name ofc
expression = Value/Number, but this can also be a name (more on names within names in Chapter 5)

Let's say you want to set the name True for the numerical value of 1. You would write the following line anywhere in your source~

.set True, 1

You can write it out in Hexadecimal as well

.set True, 0x1

With the name True set to the value of 1, you can now write True in your source wherever you need to value of 1 applied. Like this....

Code:
.set True, 1 #This line only needs to present once in your source and can be located anywhere as long as the symbol is above the instruction that uses said symbol

lwz r3, 0 (r30)
cmpwi r3, True #Use 'True' in place of numerical value 1
beq- 0xC
addi r4, r4, 4
stw r10, 0x8 (sp)

Some more Symbol examples~

.set Offset, 0x1340
.set Function_Address, 0x8045ECC4
.set Error, -1




Chapter 3: Using @h, @ha, and @l with your Symbols for Memory Addresses

Having Symbols set for commonly used Memory Addresses can come in handy. Like so...

.set Function_Address, 0x8045ECC4

Therefore, if you need to set Function_Address into a register (let's say r12), you can do so something like this...

Code:
.set Function_Address, 0x8045ECC4

lis r12, Function_Address@h
ori r12, r12, Function_Address@l
  • @h = Use the upper 16 bits of the Symbol
  • @l = Use the lower 16 bits of the Symbol

Let's say we use that same address value but instead we have it called Loading_Spot, and we need to load a word value from the address. We will use r5 for the example. You would write it out like so..

Code:
.set Loading_Spot, 0x8045ECC4

lis r5, Loading_Spot@ha
lwz r5, Loading_Spot@l (r5)

@ha = Use the upper 16 bits, but add 0x10000 to it. And makes next use of @l afterwards be sign-extended.
@l = Use the lower 16 bits.

@ha stands for High Algebraic. You need to use @ha if you are ever storing/loading to/from an Address. This is just in case the lower 16 bits of your store/load Address exceed 0x7FFF. Even if the use of @ha isn't necessary for a particular store/load, you should always be applying it as a good force of habit.



Chapter 4: Using Math, Binary, and Logical Operations within Symbols

Instead of writing just plane jane values for your Symbols. You can incorporate basic calculations. Like this..

.set add_values, 0x1000 + 0xB00
.set subtract_values, 100 - 50
.set divide_values, 33 / 11
.set multiply_values, 0xA0 * 0x14

You can beyond basic math and utilize basic binary logical operations

.set OR_values, 0x1008 | 0x400
.set AND_values, 0x800 & 0x000
.set XOR_values, 0xF8001CFD ^ 0x01000AAB

You can do non-Binary Logical Statements like this...

.set logical_and_result, 1 && 2

Please note that these type of Logical Statements (non-Binary) only output a bool value (0 or 1). The above Symbol will do a logical AND of 1 and 2. If the result is non-zero, then the Symbol 'logical_and_result' will have the value of 1 tied to it. If the result is zero, then the Symbol will have the value of 0 tied to it.

Other Logical Statement Examples...

.set logical_or_result, 278 || 000
.set logical_not_result, !(2 && 1) #This will do a Logical AND Statement, but the Result of the AND'ing is flipped.



Chapter 5: Names within Names, and Psuedo-Ops

As mentioned in chapter 2, you can use names within names for Symbols. Like this...

.set bowser, 0x1E00
.set auto_drift, 1
.set character_config, bowser | auto_drift

Another example~

.set table_address, 0x81500078
.set index_one, 4
.set index_two, index_one*2
.set index_three, index_two*2
.set table_special_data_address, table_address + index_three

As you can see, you can establish symbols that can be used directly in calculations of other symbols.

You may be in a situation where you need to create a Lookup Table (via a BL Trick), and you need plain jane numerical values written in said table, but you don't wanna go thru the hassle of setting up Symbols for every numerical value.

You can use what are referred to as "Pseudo-Ops". Here's a list of all of them.
  • .zero X #X = Amount of null bytes to write
  • .space X #Same as .zero
  • .byte X #X = byte amount to write (0x00 thru 0xFF Hex range; 0 thru 255 decimal range)
  • .short X #X = halfword amount to write (hex range 0x0000 thru 0xFFFF, decimal range 0 thru 65535)
  • .long 0xXXXXXXXX = #X = Word value to write, really no point writing these in decimal
  • .llong 0xXXXXXXXXXXXXXXXX #X = Double-word value to write, no point writing these in decimal
  • .float X #X = decimal value for single precision float, takes up one Word of space
  • .string "write string here" #Writes out a typical 8-bit ASCII string that is auto appended with a Null byte
  • .asciz "write string here" #Same as .string, but you should make a habit of using this over .string because other Assemblers (non-PPC related) may have .string not append the Null byte. So this may help you from headaches in the far future in non-PPC work stuff.
  • .ascii "write string here" Writes out a 8-bit ASCII string !!!WITHOUT!!! the null byte appended.
  • .string16 "write string here" Writes out a 16-bit ASCII (wide) string and auto appends a null halfword. This Pseudo-Op only works in the PyiiASMH family of Assemblers.

There is also one more important Pseudo-Op and that is ".align X". It aligns your block of Pseudo-Op data. This is needed if your block of data (as a total) has a size that isn't divisible by 4. You can choose how to align the block of data.

.align X Guide
  • .align 1 = Align data to make data block size have a total that is divisible by 2
  • .align 2 = Divisible by 4; WHAT YOU WILL USE 99.9% OF THE TIME!!!
  • .align 3 = Divisible by 8
  • .align 4 = Divisible by 16 aka 0x10
  • .align 5 = Divisible by 32 aka 0x20
  • .align 6 = Divisible by 64 aka 0x40

etc etc...

You SHOULD ALWAYS add in a ".align 2" after any use of any Psuedo-Op that incorporates an ASCII string. '.align 2' may also have be used if you have incorporated byte and halfword Pseudo-Ops.

The great thing about .align is that if no alignment is required, your Assembler will ignore it. Thus, no extra unnecessary null bytes are added to your code.

Confused? A picture is worth 1000 words. Take a look at the following picture (RAW option in PyiiASMH used so no Gecko related stuff is included)..

[Image: directive01.png]

As you can see the "Mario Kart Wii" string (with a null byte auto appended at the end) creates a block of data that isn't divisible by 4. Another term is that it's not "word-divisible".

Now take a look at the next picture below...

[Image: directive02.png]

As you can see we now have a .align 2 placed below the .asciz. The block of data is now aligned and divisible by 4.

A good use of Pseudo-Ops is for creating Lookup Tables for your Code. A Lookup Table is a great way to allocate a block of memory withing the code itself, and have valuable data that will be referenced/used by your Code multiple times.

Example of creating a basic Lookup Table~


Code:
bl lookup_table
.long 0x80001500
.float 3.5
.asciz "/shared2/sys/SYSCONF"
.align 2 #Make the block of data be word-divisible
lookup_table:
mflr r12 #r12 now points to start of the Lookup Table


Since the length of ASCII strings can vary, it's best to place any such string(s) at the end of your lookup table and then finish it off with a '.align 2' to enforce address alignment. If you don't place all your string(s) at the end, then extra unnecessary null bytes (auto appended by .asciz) will take up space in your Lookup Table.

You can also place label names (like how you would write branch destination spots) within a Lookup Table to 'point' to various items without any manual calculation needed. Example~

Code:
bl lookup_table

Table_Start: #label pointing to start of the Lookup Table itself which also points to the .long
.long 0x80001500

Float_Constant: #label pointing to .float
.float 3.5

File_Path: #label pointing to .asciz
.asciz "/shared2/sys/SYSCONF"
.align 2

lookup_table: #Table is complete, continue with regular PPC instructions
mflr r12 #r12 now points to start of the Lookup Table
addi r4, r12, File_Path - Table_Start #r4 now points to where the .asciz String is at within the Lookup Table.

Take a good look at the addi instruction at the very end of the above source. Notice how I implemented a basic Symbol Calculation to auto-calculate the numerical value that the addi instruction needs to use, so the addition of that value with r12 will be placed in r4. Thus, r4 will contain the Memory Address that directly points to "/shared2/sys/SYSCONF".



Chapter 6: Macros

While symbols can be handy, they are very limited. If you want PPC instruction(s) to be tied to a particular Name, you will need to use what are called Macros.

Format of a Macro~

.macro Name Optional-Arg**
contents of Macro located HERE
.endm

**Optional-Arg is optional ofc, and will be discussed in the next Chapter.

Let's say we have the following PPC instructions...

Code:
lis r12, 0x8000
lwz r12, 0x1500 (r12)
lwz r12, 0 (r12)

...And these instructions occur multiple times in your source. Well instead of 'manually' writing these batch of instructions for every single occurrence, you can write out the macro for it just once, with a name tied to it, and then literally just write out the name.

Like this..

Code:
.macro Load_Pointer #Write out the Macro, can be anywhere in your Source
lis r12, 0x8000
lwz r12, 0x1500 (r12)
lwz r12, 0 (r12)
.endm

stwu sp, 0x80 (sp)
stmw r3, 0x8 (sp)
Load_Pointer #Insert batch of instructions (aka Macro) here
mtlr r12
blrl



Chapter 7: Macros w/ Args

Now we will discuss the Optional Arguments in Macros. With the above macro example in Chapter 6, you were 'forced' to use r12. If you wanted to use a different register and keep the original macro as well, you would have to write out a whole new 2nd macro. Well, with Argument options, you wouldn't need to resort to that.

A Macro can be given arg(s) with custom names. Look at the following example..

.macro Load_Pointer register
lis \register, 0x8000
lwz \register, 0x1500 (\register)
lwz \register, 0 (\register)
.endm

As you can see, we have have the Macro equipped with 'register' as an Arg. To use the Arg within the Marco you need to prepend "\" before its name (i.e. \register). With this macro, we can now select with register to use with it. Like so...

Code:
.macro Load_Pointer register #Create Macro with 1 argument. Argument's name is register.
lis \register, 0x8000
lwz \register, 0x1500 (\register)
lwz \register, 0 (\register)
.endm

stwu sp, 0x80 (sp)
stmw r3, 0x8 (sp)
Load_Pointer r12 #Insert batch of instructions here, use r12 as the argument for the macro
mtlr r12
blrl

The Macro Argument named as 'register' allows us to choose whatever register we want to use when referencing our Macro within the Source.

Here's an another example of a Marco Arg (using custom name 'address' for the use of writing in Memory Address's)

Code:
.macro Load_Pointer address #Create Macro w/ 1 arg, titled 'address'
lis r12, \address@ha #REMEMBER WE ALWAYS USE @ha for store/loads!!!!
lwz r12, \address@l (r12)
lwz r12, 0 (r12)
.endm

stwu sp, 0x80 (sp)
stmw r3, 0x8 (sp)
Load_Pointer 0x80001500 #Use 0x80001500 for the Macro Arg
mtlr r12
blrl

Notice the comment I placed in the macro regarding @ha. Remember, that for any store/load, use @ha for establishing the upper bits of the Address! If it's not a store/load, you can simply use @h.

Fyi, you are allowed to have more than just 1 Macro Arg. Like so...

Code:
.macro Load_Pointer register, address #NOTICE the comma separating the two Args. This is needed
lis \register, \address@ha
lwz \register, \address@l (\register)
lwz \register, 0 (\register)
.endm

stwu sp, 0x80 (sp)
stmw r3, 0x8 (sp)
Load_Pointer r12, 0x80001500 #NOTICE the comma separating r12 & 0x80001500
mtlr r12
blrl




Chapter 8: Making Sources Region Friendly via If-Statements

If-Statements are really useful for having one source be able to be quickly changed on the fly before compilation in regards to differences due to Region issues. You can have one main source with If-Statements to handle Region differences instead of having multiple slightly different Sources to accommodate every Region.

MKWii has 4 regions. So writing the same source slightly different a total of 4 times would be quite annoying. Anyway, you have the following directives at your disposal.
  • .if #Starts the If-Statement
  • .elseif #If above statement is not true, a new If-Statement started
  • .else #Do task(s) below since above If-Statement(s) are not true
  • .err #Forces a Assembler halt/error
  • .abort #Does the same thing as .err. However try to stick using .err only. If you happen to do non-PPC-related assembler work, .abort on the non-PPC assembler may be deprecated.
  • .endif #End If-Statement(s)

Here is a handy template that you can use to easily handle Region-specific versions within one source.

Code:
.set region, '' #Fill in E, P, J, or K within the quotes for your region when Compiling! Lowercase letters can also be used.

.if     (region == 'E' || region == 'e') #NTSC-U (Americas)
        #PLACE NTSC-U region dependent symbols and macros HERE
.elseif (region == 'P' || region == 'p') #PAL
        #PLACE PAL region dependent symbols and macros HERE
.elseif (region == 'J' || region == 'j') #NTSC-J (Japan)
        #PLACE NTSC-J region dependent symbols and macros HERE
.elseif (region == 'K' || region == 'k') #RMCK (Korea)
        #PLACE NTSC-K region dependent symbols and macros HERE
.else #Invalid Region
        .err #Region match not detected. Tell the Assembler to halt and throw an error.
.endif

Anyway, regarding the template, it requires you fill in the Region "letter" for the source to assemble. The letter can be upper or lower case. The Assembler will assemble its contents differently depending on what Region "letter" is filled in more the ".region" Symbol.

If no Region "Letter" is used or an invalid one is supplied, the Assembler will output an Error and not even attempt to compile your source.

Here's an example of having region-specific Macros using the above template~

Code:
.set region, '' #Fill in E, P, J, or K within the quotes for your region when Compiling! Lowercase letters can also be used.

.if     (region == 'E' || region == 'e') #NTSC-U
        .macro Function_Addr register
        lis \register, 0x8000
        ori \register, \register, 0x1500
        .endm
.elseif (region == 'P' || region == 'p') #PAL
        .macro Function_Addr register
        lis \register, 0x8000
        ori \register, \register, 0x1504
        .endm
.elseif (region == 'J' || region == 'j') #NTSC-J
        .macro Function_Addr register
        lis \register, 0x8000
        ori \register, \register, 0x1508
        .endm
.elseif (region == 'K' || region == 'k') #NTSC-K
        .macro Function_Addr register
        lis \register, 0x8000
        ori \register, \register, 0x150C
        .endm
.else #Invalid Region
        .err #Region match not detected. Tell the Assembler to halt and throw an error.
.endif

add r3, r3, r14
Function_Addr r11 #Use r11 for our region-specific Macro
stw r11, 0 (r3)



Chapter 9: Conclusion + Handy Reference Page

Here's a site that covers most Assembler Directives. Keep in mind this isn't 100% accurate as the content is based on the GNU Assembler - https://sourceware.org/binutils/docs/as/Pseudo-Ops.html

For an actual real world code that uses some good macros plus symbols, check out Star's Screenshot code - https://mkwii.com/showthread.php?tid=1080

Print this item

  SYSCONF MKW Region Settings NAND Editor [Vega]
Posted by: Vega - 02-25-2019, 06:58 PM - Forum: Misc/Other - No Replies

SYSCONF MKW Region Settings NAND Editor [Vega]

This code will allow you to make permanent changes to your SYSCONF file regarding your country code, region residence code (set Flag), and globe location. I made this so you wouldn't need to use an HBC application to extract the SYSCONF file from the NAND to later Hex-edit it on a computer. Ofc, you could use some other Country/Globe Changer code, but all of those are temporary. This code makes permanent edits to your NAND.

You only need to run this code once.

XX = Country Code

YY values:
00 = No Flag, use Default Region ID Globe Location
01 = Flag On

ZZZZZZZZ = Globe Location, YY value must be 01 for this to take effect. Use a value of 00000000 if your YY value is 00.

Instructions:
Simply boot MKWii. After a split second, the TV screen will flicker a bit, then you will automatically be navigated to the Wii Main Menu. And that's it. SYSCONF edits have been made.

If you are using this code on Dolphin, the navigation to the Wii Menu might fail, but the SYSCONF edits will still be successful.

NTSC-U
C20095F4 00000028
38604000 38800020
80ADA358 80A50024
7CBA2B78 3D808022
618C9490 7D8803A6
4E800021 7C7E1B78
3F808016 4800001D
2F736861 72656432
2F737973 2F535953
434F4E46 00000000
7C6802A6 7C7D1B78
38800001 639BADBC
7F6803A6 4E800021
2C030000 418000C8
7C7F1B78 7FC4F378
38A04000 639BB15C
7F6803A6 4E800021
2C034000 408200A8
7FE3FB78 639BB2E4
7F6803A6 4E800021
2C030000 41800090
387EFFFF 38A04000
8C830001 2C040007
40A20028 88C3FFFF
2C060010 4082001C
3C80XXYY 90830001
3C80ZZZZ 6084ZZZZ
90831005 4800000C
34A5FFFF 4082FFCC
7FA3EB78 38800002
639BADBC 7F6803A6
4E800021 2C030000
41800034 7C7F1B78
7FC4F378 38A04000
639BB220 7F6803A6
4E800021 2C034000
40820014 7FE3FB78
639BB2E4 7F6803A6
4E800021 3D80801A
618C87B8 7D8803A6
4E800020 00000000

PAL
C2009634 00000028
38604000 38800020
80ADA360 80A50024
7CBA2B78 3D808022
618C9814 7D8803A6
4E800021 7C7E1B78
3F808016 4800001D
2F736861 72656432
2F737973 2F535953
434F4E46 00000000
7C6802A6 7C7D1B78
38800001 639BAE5C
7F6803A6 4E800021
2C030000 418000C8
7C7F1B78 7FC4F378
38A04000 639BB1FC
7F6803A6 4E800021
2C034000 408200A8
7FE3FB78 639BB384
7F6803A6 4E800021
2C030000 41800090
387EFFFF 38A04000
8C830001 2C040007
40A20028 88C3FFFF
2C060010 4082001C
3C80XXYY 90830001
3C80ZZZZ 6084ZZZZ
90831005 4800000C
34A5FFFF 4082FFCC
7FA3EB78 38800002
639BAE5C 7F6803A6
4E800021 2C030000
41800034 7C7F1B78
7FC4F378 38A04000
639BB2C0 7F6803A6
4E800021 2C034000
40820014 7FE3FB78
639BB384 7F6803A6
4E800021 3D80801A
618C8858 7D8803A6
4E800020 00000000

NTSC-J
C2009590 00000028
38604000 38800020
80ADA360 80A50024
7CBA2B78 3D808022
618C9734 7D8803A6
4E800021 7C7E1B78
3F808016 4800001D
2F736861 72656432
2F737973 2F535953
434F4E46 00000000
7C6802A6 7C7D1B78
38800001 639BAD7C
7F6803A6 4E800021
2C030000 418000C8
7C7F1B78 7FC4F378
38A04000 639BB11C
7F6803A6 4E800021
2C034000 408200A8
7FE3FB78 639BB2A4
7F6803A6 4E800021
2C030000 41800090
387EFFFF 38A04000
8C830001 2C040007
40A20028 88C3FFFF
2C060010 4082001C
3C80XXYY 90830001
3C80ZZZZ 6084ZZZZ
90831005 4800000C
34A5FFFF 4082FFCC
7FA3EB78 38800002
639BAD7C 7F6803A6
4E800021 2C030000
41800034 7C7F1B78
7FC4F378 38A04000
639BB1E0 7F6803A6
4E800021 2C034000
40820014 7FE3FB78
639BB2A4 7F6803A6
4E800021 3D80801A
618C8778 7D8803A6
4E800020 00000000

NTSC-K
C200973C 00000028
38604000 38800020
80ADA380 80A50024
7CBA2B78 3D808022
618C9B88 7D8803A6
4E800021 7C7E1B78
3F808016 4800001D
2F736861 72656432
2F737973 2F535953
434F4E46 00000000
7C6802A6 7C7D1B78
38800001 639BAEF8
7F6803A6 4E800021
2C030000 418000C8
7C7F1B78 7FC4F378
38A04000 639BB298
7F6803A6 4E800021
2C034000 408200A8
7FE3FB78 639BB420
7F6803A6 4E800021
2C030000 41800090
387EFFFF 38A04000
8C830001 2C040007
40A20028 88C3FFFF
2C060010 4082001C
3C80XXYY 90830001
3C80ZZZZ 6084ZZZZ
90831005 4800000C
34A5FFFF 4082FFCC
7FA3EB78 38800002
639BAEF8 7F6803A6
4E800021 2C030000
41800034 7C7F1B78
7FC4F378 38A04000
639BB35C 7F6803A6
4E800021 2C034000
40820014 7FE3FB78
639BB420 7F6803A6
4E800021 3D80801A
618C8BB4 7D8803A6
4E800020 00000000



Code creator: Vega

Code credits: Megazig (ISFS functions, _OSShutdownToSBY), RiiDefi (EGG functions), Star (Helped with Source, and provided info for certain Arguments of certain Functions)



#~~~~~~~~~~~~~~~~#
# START ASSEMBLY #
#~~~~~~~~~~~~~~~~#

#~~~~~~~~~~~~~~~#
# Address Ports #
#~~~~~~~~~~~~~~~#

#800095F4 = NTSC-U
#80009634 = PAL
#80009590 = NTSC-J
#8000973C = NTSC-K

#~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Source Region Compilation #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~#

.set region, '' #Fill in E, P, J, or K within the quotes for your region when Compiling! Lowercase letters can also be used.

#~~~~~~~~~~~~~~~~~~~~~~#
# Macros and Variables #
#~~~~~~~~~~~~~~~~~~~~~~#

.macro call_link address
  lis r12, \address@h
  ori r12, r12, \address@l
  mtlr r12
  blrl
.endm

.macro call_isfs address
  ori r27, r28, \address@l
  mtlr r27
  blrl
.endm

.macro call_nolink address
  lis r12, \address@h
  ori r12, r12, \address@l
  mtlr r12
  blr
.endm

.if    (region == 'E' || region == 'e') # RMCE
      .set ISFS_Open, 0xADBC
      .set ISFS_Read, 0xB15C
      .set ISFS_Write, 0xB220
      .set ISFS_Close, 0xB2E4
      .set Wii_Menu, 0x801A87B8
      .set Egg_Alloc, 0x80229490
.elseif (region == 'P' || region == 'p') # RMCP
      .set ISFS_Open, 0xAE5C
      .set ISFS_Read, 0xB1FC
      .set ISFS_Write, 0xB2C0
      .set ISFS_Close, 0xB384
      .set Wii_Menu, 0x801A8858
      .set Egg_Alloc, 0x80229814
.elseif (region == 'J' || region == 'j') # RMCJ
      .set ISFS_Open, 0xAD7C
      .set ISFS_Read, 0xB11C
      .set ISFS_Write, 0xB1E0
      .set ISFS_Close, 0xB2A4
      .set Wii_Menu, 0x801A8778
      .set Egg_Alloc, 0x80229734
.elseif (region == 'K' || region == 'k') # RMCK
      .set ISFS_Open, 0xAEF8
      .set ISFS_Read, 0xB298
      .set ISFS_Write, 0xB35C
      .set ISFS_Close, 0xB420
      .set Wii_Menu, 0x801A8BB4
      .set Egg_Alloc, 0x80229B88
.else # Invalid Region
      .err
.endif

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#                        Register Notes:                        #
# No need to backup anything as final function is OSReturnToMenu #
#        r31 = Backup Register for File Descriptor Values        #
#        r30 = Backup Register for Heap Address Pointer        #
#      r29 = Backup Register for File Path for ISFS_Open        #
#                  r28 = Used for ISFS Macros                  #
#                  r27 = Used for ISFS Macros                  #
#          r26 = Backup for System Heap Calc Address            #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

#~~~~~~~~~~~~~~~~~~~~~~~#
#    Egg::Heap::alloc  #
#  r3 = Size of Heap  #
#    r4 = Alignment    #
# r5 = System Heap Calc #
#~~~~~~~~~~~~~~~~~~~~~~~#

li r3, 0x4000 #Size of SYSCONF is 0x4000
li r4, 0x20 #32 bit alignment

.if    (region == 'E' || region == 'e')
      lwz r5, -0x5CA8(r13)
.elseif (region == 'P' || region == 'p')
      lwz r5, -0x5CA0(r13)
.elseif (region == 'J' || region == 'j')
      lwz r5, -0x5CA0(r13)
.elseif (region == 'K' || region == 'k')
      lwz r5, -0x5C80(r13)
.endif

lwz r5, 0x0024 (r5)
mr r26, r5 #Backup System Heap Calc Address

call_link Egg_Alloc

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Backup Heap Pointer; Set ISFS Function 1st Half Address #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mr r30, r3
lis r28, 0x8016

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#    ISFS_Open (#1) Arguments      #
# r3 = Address Pointer To File Path #
# r4 = 0x1 for ISFS_Read Permission #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

bl file_path

.llong 0x2F73686172656432 #String for /shared2/sys/SYSCONF
.llong 0x2F7379732F535953
.long 0x434F4E46
.space 4 #4 bytes of zeros added for alignment

file_path:
mflr r3
mr r29, r3 #Backup File Path Address Pointer to r29 for later 2nd use of ISFS_Open
li r4, 1

call_isfs ISFS_Open

cmpwi r3, 0
blt- the_end
mr r31, r3 #Backup file descriptor

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#                      ISFS_Read Arguments                        #
#                      r3 = File Descriptor                      #         
# r4 = Address Pointer to Dump Data from File to (32 bit aligned) #
#                r5 = Amount of Bytes to Dump                    #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mr r4, r30
li r5, 0x4000

call_isfs ISFS_Read
cmpwi r3, 0x4000
bne- the_end

#~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# ISFS_Close (#1) Arguments #
#    r3 = File Descriptor  #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mr r3, r31 #Move backed up file descriptor to r3
call_isfs ISFS_Close
cmpwi r3, 0
blt- the_end

#~~~~~~~~~~~~~~~~~#
# Pre-Loop Config #
#~~~~~~~~~~~~~~~~~#

addi r3, r30, -1 #Minus one from the heap address pointer, result in r3
li r5, 0x4000

#~~~~~~~~~~#
# the_loop #
#~~~~~~~~~~#

the_loop:
lbzu r4, 0x1 (r3) #Every time this instruction is executed, r3 increases by 0x1
cmpwi r4, 0x7 #The value after the byte 0x07 is usually the country code, but we have to double check
bne+ decrement_loop #Most likely byte value is not 7, if not 7, decrement the loop

#~~~~~~~~~~~~~~~~~~~~~~~~~#
# Double Check Byte Value #
#~~~~~~~~~~~~~~~~~~~~~~~~~#

lbz r6, -0x1 (r3) #Load Byte value that is -0x1 away from 0x7 (have to do offset of -0x2 because of the lbzu instruction)
cmpwi r6, 0x10 #Compare Byte to 0x10
bne- decrement_loop #If not equal to 0x10, we are still not in the correct spot of SYSCONF, decrement loop. Unsure about branch probability, left it default (less likely)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# On Correct Location of SYSCONF, Write New Values #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

lis r4, 0x8801 #Country Code followed by Region Residence Code (set flag); Korea w/ Flag On used purely for Compilation!
stw r4, 0x1 (r3) #Store Country Code and Region Residence Code to our temp SYSCONF file
lis r4, 0x3FFF #Set 1st half Globe Location (north pole with slight spin used purely for Compilation!)
ori r4, r4, 0x7500 #Set 2nd half Globe Location
stw r4, 0x1005 (r3) #Store Globe Location to our temp SYSCONF file
b start_open_write #No need for loop to continue since edits to file are completed

#~~~~~~~~~~~~~~~~#
# Decrement Loop #
#~~~~~~~~~~~~~~~~#

decrement_loop:
subic. r5, r5, 1 #Every time this instruction is executed, subtract 1 from r5. Update the Condition Register (cmpwi r5, 0x0)
bne+ the_loop #If not equal to 0x0, run the loop again

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#          ISFS_Open (2nd time)          #
# r4 is now 0x2 for ISFS_Write Permissions #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

start_open_write:
mr r3, r29 #Move backed up file path address pointer to r3
li r4, 0x2

call_isfs ISFS_Open

cmpwi r3, 0
blt- the_end
mr r31, r3 #Backup new file descriptor

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#                  ISFS_Write Arguments                    #
#                  r3 = File Descriptor                    #
# r4 = Address Pointer to Data that will be Written to File #
#            r5 = Amount of Bytes to Write                #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mr r4, r30 #Move backed up Heap Address Pointer to r4
li r5, 0x4000

call_isfs ISFS_Write

cmpwi r3, 0x4000
bne- the_end

#~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# ISFS_Close (#1) Arguments #
#    r3 = File Descriptor  #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~#

mr r3, r31 #Place fd back into r3
call_isfs ISFS_Close

#No need to check return of Close since code is now ending

#~~~~~~~~~~~~~~~~#
# OSReturnToMenu #
#~~~~~~~~~~~~~~~~#

the_end:
call_nolink Wii_Menu

#~~~~~~~~~~~~~~#
# END ASSEMBLY #
#~~~~~~~~~~~~~~#

Print this item

  Screenshot [Star]
Posted by: Star - 02-23-2019, 06:14 PM - Forum: Misc/Other - No Replies

Screenshot [Star]

This code will allow you to take a screenshot, anytime, at the press of a button.

(NTSC-U)
04009644 818C0020
2834XXXX YYYYZZZZ
C2009644 00000046
818C0020 9421FF30
BC410008 48000015
2F736372 65656E73
686F7473 00000000
7C6802A6 38800000
38A00003 38C00003
38E00003 3FE08016
63EC9DD4 7D8903A6
4E800421 2C03FF97
41A2000C 2C030000
408201D0 3D80801A
618CACBC 7D8903A6
4E800421 38A10080
3D80801A 618CAF08
7D8903A6 4E800421
386100A8 4800002D
2F736372 65656E73
686F7473 2F253032
64253032 64253032
64253032 64253032
64253032 64000000
7C8802A6 80A10094
38C00064 7CE533D6
7CC731D6 7CA62850
80C10090 38C60001
80E1008C 81010088
81210084 81410080
4CC63182 3D808001
618C0ECC 7D8903A6
4E800421 2C030019
40820130 386100A8
38800000 38A00003
38C00003 38E00003
63ECABD4 7D8903A6
4E800421 2C030000
40820108 386100A8
38800002 63ECADBC
7D8903A6 4E800421
2C030000 418000EC
7C7E1B78 38600008
38800020 80ADA358
7CBD2B78 80A50024
7CBC2B78 3D808022
618C9490 7D8903A6
4E800421 2C030000
418200A8 7C7B1B78
3C805354 60844102
90830000 809D0048
80840000 7C9A2378
80840000 90830004
3F20CD80 807900C0
60630020 907900C0
7FC3F378 7F64DB78
38A00008 63ECB220
7D8903A6 4E800421
2C030008 40820030
7FC3F378 809A0004
A0BA0000 A0DA0002
38A5000F 54A50436
7CA531D6 54A5083C
63ECB220 7D8903A6
4E800421 807900C0
546306F2 907900C0
7F63DB78 7F84E378
3D808022 618C9800
7D8903A6 4E800421
7FC3F378 63ECB2E4
7D8903A6 4E800421
B8410008 382100D0
60000000 00000000
E0000000 80008000

(PAL)
04009684 818C0020
2834XXXX YYYYZZZZ
C2009684 00000046
818C0020 9421FF30
BC410008 48000015
2F736372 65656E73
686F7473 00000000
7C6802A6 38800000
38A00003 38C00003
38E00003 3FE08016
63EC9E74 7D8903A6
4E800421 2C03FF97
41A2000C 2C030000
408201D0 3D80801A
618CAD5C 7D8903A6
4E800421 38A10080
3D80801A 618CAFA8
7D8903A6 4E800421
386100A8 4800002D
2F736372 65656E73
686F7473 2F253032
64253032 64253032
64253032 64253032
64253032 64000000
7C8802A6 80A10094
38C00064 7CE533D6
7CC731D6 7CA62850
80C10090 38C60001
80E1008C 81010088
81210084 81410080
4CC63182 3D808001
618C1A2C 7D8903A6
4E800421 2C030019
40820130 386100A8
38800000 38A00003
38C00003 38E00003
63ECAC74 7D8903A6
4E800421 2C030000
40820108 386100A8
38800002 63ECAE5C
7D8903A6 4E800421
2C030000 418000EC
7C7E1B78 38600008
38800020 80ADA360
7CBD2B78 80A50024
7CBC2B78 3D808022
618C9814 7D8903A6
4E800421 2C030000
418200A8 7C7B1B78
3C805354 60844102
90830000 809D0048
80840000 7C9A2378
80840000 90830004
3F20CD80 807900C0
60630020 907900C0
7FC3F378 7F64DB78
38A00008 63ECB2C0
7D8903A6 4E800421
2C030008 40820030
7FC3F378 809A0004
A0BA0000 A0DA0002
38A5000F 54A50436
7CA531D6 54A5083C
63ECB2C0 7D8903A6
4E800421 807900C0
546306F2 907900C0
7F63DB78 7F84E378
3D808022 618C9B84
7D8903A6 4E800421
7FC3F378 63ECB384
7D8903A6 4E800421
B8410008 382100D0
60000000 00000000
E0000000 80008000

(NTSC-J)
040095E0 818C0020
2834XXXX YYYYZZZZ
C20095E0 00000046
818C0020 9421FF30
BC410008 48000015
2F736372 65656E73
686F7473 00000000
7C6802A6 38800000
38A00003 38C00003
38E00003 3FE08016
63EC9D94 7D8903A6
4E800421 2C03FF97
41A2000C 2C030000
408201D0 3D80801A
618CAC7C 7D8903A6
4E800421 38A10080
3D80801A 618CAEC8
7D8903A6 4E800421
386100A8 4800002D
2F736372 65656E73
686F7473 2F253032
64253032 64253032
64253032 64253032
64253032 64000000
7C8802A6 80A10094
38C00064 7CE533D6
7CC731D6 7CA62850
80C10090 38C60001
80E1008C 81010088
81210084 81410080
4CC63182 3D808001
618C1950 7D8903A6
4E800421 2C030019
40820130 386100A8
38800000 38A00003
38C00003 38E00003
63ECAB94 7D8903A6
4E800421 2C030000
40820108 386100A8
38800002 63ECAD7C
7D8903A6 4E800421
2C030000 418000EC
7C7E1B78 38600008
38800020 80ADA360
7CBD2B78 80A50024
7CBC2B78 3D808022
618C9734 7D8903A6
4E800421 2C030000
418200A8 7C7B1B78
3C805354 60844102
90830000 809D0048
80840000 7C9A2378
80840000 90830004
3F20CD80 807900C0
60630020 907900C0
7FC3F378 7F64DB78
38A00008 63ECB1E0
7D8903A6 4E800421
2C030008 40820030
7FC3F378 809A0004
A0BA0000 A0DA0002
38A5000F 54A50436
7CA531D6 54A5083C
63ECB1E0 7D8903A6
4E800421 807900C0
546306F2 907900C0
7F63DB78 7F84E378
3D808022 618C9AA4
7D8903A6 4E800421
7FC3F378 63ECB2A4
7D8903A6 4E800421
B8410008 382100D0
60000000 00000000
E0000000 80008000

(NTSC-K)
0400978C 818C0020
2833XXXX YYYYZZZZ
C200978C 00000046
818C0020 9421FF30
BC410008 48000015
2F736372 65656E73
686F7473 00000000
7C6802A6 38800000
38A00003 38C00003
38E00003 3FE08016
63EC9F10 7D8903A6
4E800421 2C03FF97
41A2000C 2C030000
408201D0 3D80801A
618CB0B8 7D8903A6
4E800421 38A10080
3D80801A 618CB304
7D8903A6 4E800421
386100A8 4800002D
2F736372 65656E73
686F7473 2F253032
64253032 64253032
64253032 64253032
64253032 64000000
7C8802A6 80A10094
38C00064 7CE533D6
7CC731D6 7CA62850
80C10090 38C60001
80E1008C 81010088
81210084 81410080
4CC63182 3D808001
618C1A94 7D8903A6
4E800421 2C030019
40820130 386100A8
38800000 38A00003
38C00003 38E00003
63ECAD10 7D8903A6
4E800421 2C030000
40820108 386100A8
38800002 63ECAEF8
7D8903A6 4E800421
2C030000 418000EC
7C7E1B78 38600008
38800020 80ADA380
7CBD2B78 80A50024
7CBC2B78 3D808022
618C9B88 7D8903A6
4E800421 2C030000
418200A8 7C7B1B78
3C805354 60844102
90830000 809D0048
80840000 7C9A2378
80840000 90830004
3F20CD80 807900C0
60630020 907900C0
7FC3F378 7F64DB78
38A00008 63ECB35C
7D8903A6 4E800421
2C030008 40820030
7FC3F378 809A0004
A0BA0000 A0DA0002
38A5000F 54A50436
7CA531D6 54A5083C
63ECB35C 7D8903A6
4E800421 807900C0
546306F2 907900C0
7F63DB78 7F84E378
3D808022 618C9EF8
7D8903A6 4E800421
7FC3F378 63ECB420
7D8903A6 4E800421
B8410008 382100D0
60000000 00000000
E0000000 80008000

Notes:
- Extreme overuse of this code may cause wear to the Wii's NAND memory.

Code Creator: Star
Code Credits: Riidefi

Print this item

  Future Fly (Wii Chuck) [mdmwii]
Posted by: Vega - 02-18-2019, 09:07 PM - Forum: Offline Non-Item - Replies (7)

Future Fly (Wii Chuck) [mdmwii]

For Wii Chuck only.

This code is an enhancement of the original Free Fly Code. When the race/battle starts, press your button activate to turn on the code. Use the analog stick to navigate your direction of flight, it has complete range of motion.

Button map:
D-Pad Up = Activate & Vertically Up
D-Pad Down = Vertically Down
D-Pad Left = Strafe Left
D-Pad Right = Strafe Right
Stick Up = Turn Up
Stick Down = Turn Down
Stick Left = Turn Left
Stick Right = Turn Right
A = Forward
B = Backward
A + B = Deactivate

This code makes use of memory addresses 0x80001534 thru 0x80001537, and 0x80001600 thru 0x8000161B, make sure no other codes in your GCT/Cheat-Manager are using those addresses!

NTSC-U
04001600 43700000
04001604 42F00000
04001610 BD500000
04001614 BD800000
04001618 00000001
C27E4C98 00000003
3DE08000 5460063E
1E600004 926F1534
60000000 00000000
0400161C 00000000
28341462 FFF70008
C25AA6FC 00000029
EC7A01F2 3E408000
3DE08034 3DC0809C
81CED110 81CE0020
82721534 C2321600
7DCE9A14 81CE0000
81CE0024 81CEFFF8
81CE0008 81CE0008
39CE0010 7C0EF000
40820100 C03E0068
C33E006C C2FE0070
3DC0808B C20E053C
A1CF1462 71D30008
2C130008 40820008
EF39882A 71D30004
2C130004 40820008
EF398828 A1CF1462
FE408850 FE30946E
71D30001 2C130001
4082000C FE208850
48000010 71D30002
2C130002 4082001C
C27EFF8C EE730472
EC219828 C27EFFAC
EE730472 EEF79828
A1CF1462 C2521610
FE209050 FE508CAE
C2321600 71D30400
2C130400 40820014
C2321604 FE208850
FE409050 48000010
71D30800 2C130800
40820028 C27EFF94
EE730472 EC21982A
C27EFFA4 EE730472
EF39982A C27EFFB4
EE730472 EEF7982A
C26F14C0 EE5204F2
D25E00E8 C26F14C4
FE609850 C2321614
EE3104F2 D23E00E4
60000000 00000000
28341463 F3FF0C00
045AA6FC EC7A01F2
E0000000 80008000

PAL
04001600 43700000
04001604 42F00000
04001610 BD500000
04001614 BD800000
04001618 00000001
C27EEFA8 00000003
3DE08000 5460063E
1E600004 926F1534
60000000 00000000
0400161C 00000000
283457E2 FFF70008
C25B5624 00000029
EC7A01F2 3E408000
3DE08034 3DC0809C
81CE18F8 81CE0020
82721534 C2321600
7DCE9A14 81CE0000
81CE0024 81CEFFF8
81CE0008 81CE0008
39CE0010 7C0EF000
40820100 C03E0068
C33E006C C2FE0070
3DC0808B C20E4BEC
A1CF57E2 71D30008
2C130008 40820008
EF39882A 71D30004
2C130004 40820008
EF398828 A1CF57E2
FE408850 FE30946E
71D30001 2C130001
4082000C FE208850
48000010 71D30002
2C130002 4082001C
C27EFF8C EE730472
EC219828 C27EFFAC
EE730472 EEF79828
A1CF57E2 C2521610
FE209050 FE508CAE
C2321600 71D30400
2C130400 40820014
C2321604 FE208850
FE409050 48000010
71D30800 2C130800
40820028 C27EFF94
EE730472 EC21982A
C27EFFA4 EE730472
EF39982A C27EFFB4
EE730472 EEF7982A
C26F5840 EE5204F2
D25E00E8 C26F5844
FE609850 C2321614
EE3104F2 D23E00E4
60000000 00000000
283457E3 F3FF0C00
045B5624 EC7A01F2
E0000000 80008000

NTSC-J
04001600 43700000
04001604 42F00000
04001610 BD500000
04001614 BD800000
04001618 00000001
C27EE614 00000003
3DE08000 5460063E
1E600004 926F1534
60000000 00000000
0400161C 00000000
28345162 FFF70008
C25B4FA4 00000029
EC7A01F2 3E408000
3DE08034 3DC0809C
81CE0958 81CE0020
82721534 C2321600
7DCE9A14 81CE0000
81CE0024 81CEFFF8
81CE0008 81CE0008
39CE0010 7C0EF000
40820100 C03E0068
C33E006C C2FE0070
3DC0808B C20E3D4C
A1CF5162 71D30008
2C130008 40820008
EF39882A 71D30004
2C130004 40820008
EF398828 A1CF5162
FE408850 FE30946E
71D30001 2C130001
4082000C FE208850
48000010 71D30002
2C130002 4082001C
C27EFF8C EE730472
EC219828 C27EFFAC
EE730472 EEF79828
A1CF5162 C2521610
FE209050 FE508CAE
C2321600 71D30400
2C130400 40820014
C2321604 FE208850
FE409050 48000010
71D30800 2C130800
40820028 C27EFF94
EE730472 EC21982A
C27EFFA4 EE730472
EF39982A C27EFFB4
EE730472 EEF7982A
C26F51C0 EE5204F2
D25E00E8 C26F51C4
FE609850 C2321614
EE3104F2 D23E00E4
60000000 00000000
28345163 F3FF0C00
045B4FA4 EC7A01F2
E0000000 80008000

NTSC-K
04001600 43700000
04001604 42F00000
04001610 BD500000
04001614 BD800000
04001618 00000001
C27DD368 00000003
3DE08000 5460063E
1E600004 926F1534
60000000 00000000
0400161C 00000000
283337E2 FFF70008
C25A367C 00000029
EC7A01F2 3E408000
3DE08033 3DC0809B
81CEFF38 81CE0020
82721534 C2321600
7DCE9A14 81CE0000
81CE0024 81CEFFF8
81CE0008 81CE0008
39CE0010 7C0EF000
40820100 C03E0068
C33E006C C2FE0070
3DC0808B C20E3064
A1CF37E2 71D30008
2C130008 40820008
EF39882A 71D30004
2C130004 40820008
EF398828 A1CF37E2
FE408850 FE30946E
71D30001 2C130001
4082000C FE208850
48000010 71D30002
2C130002 4082001C
C27EFF8C EE730472
EC219828 C27EFFAC
EE730472 EEF79828
A1CF37E2 C2521610
FE209050 FE508CAE
C2321600 71D30400
2C130400 40820014
C2321604 FE208850
FE409050 48000010
71D30800 2C130800
40820028 C27EFF94
EE730472 EC21982A
C27EFFA4 EE730472
EF39982A C27EFFB4
EE730472 EEF7982A
C26F3840 EE5204F2
D25E00E8 C26F3844
FE609850 C2321614
EE3104F2 D23E00E4
60000000 00000000
283337E3 F3FF0C00
045A367C EC7A01F2
E0000000 80008000

Code creator: mdmwii
Code credits: Mrmk (certain instructions ported to make other regions work)

Print this item

  Launch Any Wii Channel [Vega]
Posted by: Vega - 02-18-2019, 08:41 PM - Forum: Incomplete & Outdated Codes - Replies (4)

Launch Any Wii Channel [Vega]

NOTE: Outdated by version in main codes forum

Press your button activator at any time to launch the desired Wii Channel of your choice.

This code does not work for launching HBC.

NTSC-U
2834XXXX YYYYZZZZ
C20095F4 00000006
3C60UUUU 6063UUUU
3C80LLLL 6084LLLL
3CA00301 38C00000
3D80801A 618CDEC0
7D8803A6 4E800020
60000000 00000000
E0000000 80008000

PAL
2834XXXX YYYYZZZZ
C2009634 00000006
3C60UUUU 6063UUUU
3C80LLLL 6084LLLL
3CA00301 38C00000
3D80801A 618CDF60
7D8803A6 4E800020
60000000 00000000
E0000000 80008000

NTSC-J
2834XXXX YYYYZZZZ
C2009590 00000006
3C60UUUU 6063UUUU
3C80LLLL 6084LLLL
3CA00301 38C00000
3D80801A 618CDE80
7D8803A6 4E800020
60000000 00000000
E0000000 80008000

NTSC-K
2833XXXX YYYYZZZZ
C200973C 00000006
3C60UUUU 6063UUUU
3C80LLLL 6084LLLL
3CA00301 38C00000
3D80801A 618CE2BC
7D8803A6 4E800020
60000000 00000000
E0000000 80008000

UUUUUUUU = Upper 32 bits of Title ID
LLLLLLLL = Lower 32 bits of Title ID

Example U/L value:
00010002 48414341 = Launch Mii Channel (non-Korean)




Source (Mii channel;non Korean used for Title ID):

#~~~~~~~~~~~~~~~~#
# START ASSEMBLY #
#~~~~~~~~~~~~~~~~#

#

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# PAL Specific Source for Compilation #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#    OSLaunchTitleI Arguments    #
# r3 = Upper 32 bits of Title ID #
# r4 = Lower 32 bits of Title ID #
#        r5 = 0x03010000         #
#           r6 = Zero            #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

lis r3, 0x0001 #Load 0x0001 into upper 16 bits of r3, lower 16 bits cleared
ori r3, r3, 0x0002 #Load 0x0002 into lower 16 bits of r3
lis r4, 0x4841 #Load 0x4841 into upper 16 bits of r4, lower 16 bits are cleared
ori r4, r4, 0x4341 # #Load 0x4341 into lower 16 bits of r4
lis r5, 0x0301 #Load 0x0301 into upper 16 bits of r5, lower 16 bits are cleared
li r6, 0x0 #Clear out r6

#~~~~~~~~~~~~~~~~~~~~~#
# Call OSLaunchTitleI #
# NTSC-U = 0x801ADEC0 #
#   PAL = 0x801ADF60  #
# NTSC-J = 0x801ADE80 #
# NTSC-K = 0x801AE2BC #
#~~~~~~~~~~~~~~~~~~~~~#

lis r12, 0x801A #Load 0x801A into upper 16 bits of r12, lower 16 bits are cleared
ori r12, r12, 0xDF60 #Load 0xDF60 into lower 16 bits of r12
mtlr r12 #Copy the value of r12 to the Link Register
blr #Branch to Link Register; Call the function

#

#~~~~~~~~~~~~~~#
# END ASSEMBLY #
#~~~~~~~~~~~~~~#




Code creator: Vega
Code credits: Megazig (OSLaunchTitleI)

Print this item