Basic GVR Usage in ASM Codes
#1
Basic GVR Usage in ASM Codes

For Beginner ASM Coders.



Chapter 1: Intro; Explaining more about C2 Codes

C2 'Insert ASM' Codes are executed by the Code Handler when its Hook Address is executed by Broadway. For a full refresher regarding this, reread Chapter 3 of this thread -> https://mariokartwii.com/showthread.php?tid=1383

A C2 ASM Code can be executed for game specific list/cycle of circumstances. What do I mean by that?

Well for Mario Kart Wii, many addresses that are used by C2 Codes will be executed in a cycle for each player/CPU. An address will be executed for Player 1. Then next time that the game executes said address, it will be for Player 2. Then Player 3, 4, 5, etc etc.

For a game like Dragon Ball Z Budokai Tenkaichi 3 (where a match is typically Player 1 vs Player 2/COM), an address can be executed first for Player 1, then next time it will be for Player 2/COM.

Understanding this is crucial to reaching to that 'next level' of ASM Coding. This may not seem important at first, but this will open up a variety of possibilities for your future Codes.



Chapter 2: What is a GVR? Why do values in the GVRs matter?

GVR = Global Variable Register

It is any General Purpose Register that is r14 thru r31. GVRs will contain values such as...
  • Player Number/Slot
  • CPU Number/Slot
  • Course Number/Slot
  • Position Value
  • Menu/Mode Type Number/Slot
  • etc

Therefore, during the time when your ASM Code is executing, the GVRs may contain data that is relevant to improving your Code. By the way, the term "slot" is preferred by most Coders over the term "number". Regarding Player Slots, for the majority of cases, Slot value of 0 represents Player 1 (1st non-CPU Player).

By figuring out which GVR contains a specific slot value, you can modify your ASM Codes to only execute when said GVR has a certain value. A big issue for new Coders is creating a code and running into an issue where it applies to both the Human Player and the CPU (when the Coder only wants their Code to execute for the Human Player). At this point, if said Coder isn't familiar with GVR data, he/she will have literally zero idea on how to fix their code.



Chapter 3: Let's Make a Code using GVR Data; Part 1

We will use the old historical version of the Mario Kart Wii Shared Item Code (PAL) for demonstrating GVR fundamentals

Code:
C27BA164 00000002
386000WW 90770020
60000000 00000000

This code simply changes what item you receive from the item box when you pick it up. WW = Item to Receive, we will set this to 00 (Green Shell) for this GVR tutorial.

Code:
C27BA164 00000002
38600000 90770020
60000000 00000000

Now let's inspect the source...

Code:
li r3, 0 #Set Item (green shell)
stw r3, 0x0020 (r23) #Default/Original Instruction of Hook Address. This stores the Item to Dynamic Memory.

At this moment we have no idea what data is represented in any of the GVRs. If you have MKWii, launch it on Dolphin. Do NOT apply the Shared Item Code. If you don't have MKWii, be sure to examine the following screenshots closely to follow along. Once you have launched MKWii, do a normal Offline Race. Simply pick Luigi Circuit (as that is the track I did for the exercise, and this plays an important role to the explanation of the final screenshot in this Chapter). Character+Vehicle combo doesn't matter, pick anything. Sometime before the Race begins, pause the emulation & set an Instruction BP on Address 807BA164.

[Image: gvr01.png]

Once you have the Breakpoint set go ahead and start the race, but sit at the start line. When the first CPU hits the item box, the BP will break/hit. Note down the r14 thru r31 data that you see.

[Image: gvr02.png]

Once you have that all noted down, while keeping the Breakpoint ON, resume the emulation. It will pause again once another CPU hits an item box. Take a look at r14 thru r31. If any values changed from the previous Instruction BP hit, they will be in Red font. Note down the Red font GVR values only.

[Image: gvr03.png]

While still keeping the Breakpoint ON, resume the emulation again. It will pause again after another Item Box hit. Take a look at the previous BP-hit Red font GVR values. How do they differ from the previous BP-hit vs the latest BP-hit? Note this all down (including their new current values).

[Image: gvr04.png]

In the above screen shot, there is something that sort of has a pattern to it. It's r25. We see that it has been incrementing (1 to 2 to 4). Fyi this WILL differ slightly on your own test. But you will see that r25 is indeed incrementing.

Go ahead and repeat the process until all CPUs have passed the first row of item boxes. Once they have pass that first row, go ahead and manually pause the emulation to prevent any further item box hits. Be sure to pause the emulation before any of the CPU players hit the next Item Box row.

Here are the rest of my screenshots of all BP-hits for once the CPU's got passed the first row of Items. Keep your mind your r25 values will differ, but they should be incrementing.

[Image: gvr05.png]

[Image: gvr06.png]

You can see that r25 is definitely incrementing. What could it be? Could this value be the Player's/CPU's assigned slot value. Well the odds of Slot Value increasing every BP hit is pretty low. So r25 is probably not a slot value.

Well we know the first CPU to hit the box is very likely to be in first place. In fact, said CPU WILL be 1st place unless said CPU somehow missed picking up the very first box in the race, which is essentially impossible.

Thus, we can safely conclude that r25 represents the Player's/CPU's Position in the Race (at the time when they picked up the Item Box).

To further prove this is true, here is the next screenshot of once the 1st place CPU has made contact with the next Item Box Row (when I did this exercise). All CPUs have already went past the first row of boxes (on Luigi Circuit ofc), and now we can see from the screenshot that 1st Place CPU has picked up the first box on the next item box row on the track.

[Image: gvr07.png]

And the screenshot proves to us that r25 is 1, as expected. So now we know for near 100% certainty that r25 = Position. 1 = 1st Place, 2 = 2nd Place, etc etc til C = 12th (last) Place.



Chapter 4: Let's Make a Code using GVR Data; Part 2

Awesome, we have some GVR data in which we can make a code with. Let's say you only wanted the Shared Item Code to execute whenever the Player/CPU is in last (12th place). Before we have anything at all execute in this new code we are writing, the 'check' for r25's value needs to be placed in first.

We will use a simple Compare Word Immediate (cmpwi) instruction. Now, since we only want the Code to execute when Player/CPU is in 12th place, we will obviously check r25's value against the value of 0xC (12).

Code:
cmpwi r25, 0xC #12

We have a comparison instruction written out. Let's now write the Branch instruction. Well, we know that we do NOT want the code to execute if r25 isn't 12, so we will be using a Branch-If-Not-Equal (bne) instruction.

Code:
cmpwi r25, 0xC
bne

Since there are 12 different total positions, the odds of r25 NOT being 12 is high, thus we can supply a + symbol to the branch instruction to give a small hint to Broadway that the Branch Instruction will most likely occur. The branch hint is optional.

Code:
cmpwi r25, 0xC
bne+

Now we need a label name. We will simply call it jump_code.

Code:
cmpwi r25, 0xC
bne+ jump_code

Underneath the branch instruction, we will put the instructions from the original Shared Item Code. Therefore if r25 is equal to 0xC (12), it will NOT take the branch jump and execute the instructions directly below the bne instruction.

Code:
cmpwi r25, 0xC #Check if in Last Place
bne+ jump_code #If not, take branch and don't execute code

li r3, 0 #Set Green Shell
stw r3, 0x0020 (r23) #Default/original instruction

At this point, you may be thinking to place the branch's jump 'landing spot' label at the very end, and the code is complete. However that would be wrong, we will write it out below and I will explain why that is incorrect.

Code:
cmpwi r25, 0xC #Check if in Last Place
bne+ jump_code #If not, take branch and don't execute code

li r3, 0 #Set Green Shell
stw r3, 0x0020 (r23) #Default/original instruction

jump_code:

Why is this wrong? Well, what happens if r25 isn't 12 and the branch is taken? You will completely skip over the Default Instruction. We need that instruction to always be executed. This is because we must always have the r3 value be stored to Dynamic Memory. With that al being said, we need the 'jump_code:' label right before the Default instruction. Like this...

Code:
cmpwi r25, 0xC #Check if in Last Place
bne+ jump_code #If not, take branch and don't execute code

li r3, 0 #Set Green Shell

jump_code:
stw r3, 0x0020 (r23) #Default/original instruction

Now assemble that code in your Assembler using Address (PAL) 0x807BA164. You should get the following code...

Code:
C27AB704 00000003
2C19000C 40A20008
38600000 90770020
60000000 00000000

We know from earlier that the '38600000' line of the Code is the 'li r3, 0' instruction. We can change that back to 38600WW to allow the end user to set a custom Item Value for the Code.

The first instruction of our new code is the cmpwi r25, 0xC. We can also configure that assembled line of code to filled in by the User, we will implement a P value for that.

PAL Positional Shared Item Code
P = Position Required
WW = Item to Receive

C27AB704 00000003
2C19000P 40A20008
386000WW 90770020
60000000 00000000


Congrats, you've just remade Star's Positional Shared Item Code! Link - https://mariokartwii.com/showthread.php?tid=536
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)