Using the Exception Vector Area in ASM Codes
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...

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.

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

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

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.

Forum Jump:

Users browsing this thread: 1 Guest(s)