Logging game events to text file
#11
(03-08-2024, 06:44 PM)Vega Wrote: and as long as Dolphin logs in Register info for Instruction BPs, then you should be able to do all the logic in Chataigne with Option 1.

Yeah, unfortunately, it seems I can only log breakpoints at memory addresses.  I'm really trying my best here, I promise, I've read through the entirety of the ASM tutorial and I'm about halfway towards actually understanding it.  Just answer me this - is the item for each player stored somewhere, whether that be a register, or a part of the memory? Is that place consistent?  Because in that GVR tutorial you linked, the source code is

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.
Which suggests you're putting the green shell in register 3, and then taking that value and putting it into memory value of 0x0020 + r23, which equals 00000000.  So...you're putting it in 00000020?  That doesn't make sense.  Maybe you're putting it in 80000020?  Nope, can't be, when I have a triple mushroom in my inventory that byte is 0D, which according to this should be a POW block.

I'm honestly getting totally lost here.  To add even more confusion, this code somehow affects items without using the registers at all, just a nop on a memory value.  This is frustrating, all I wanted to do was create a cool light show.
Reply
#12
Wink 
HUGE News: I got 2/3 of my goals completed!!  Using Lightning Shock Length Modifier and Blooper Ink Timer Modifier, both by 1superchip, I was able to find the memory breakpoint for "someone used lightning" and "someone used a blooper".  I added a memory instruction read breakpoints on these two addresses:

8088D508 for lightning
808B12F4 for blooper

Now, whenever anyone uses lightning, Dolphin will log:

Code:
Core\PowerPC\BreakPoints.cpp:381 N[MI]: MBP 80579c94 ( --- ) Read16 2b2 at 8088d508 ( --- )

And whenever anyone uses a blooper, Dolphin will log:

Code:
Core\PowerPC\BreakPoints.cpp:381 N[MI]: MBP 80578814 ( --- ) Read16 1c2 at 808b12f4 ( --- )


which lets Chataigne know to trigger the proper effect with my RGB lights.  This means I'm more than halfway there, and as meatloaf would say, two out of three ain't bad.  So far we got:

✓ Log when anyone uses lightning
✓ Log when anyone uses blooper
X Log when a human uses a star

Now, the star thing may have to do with registers and slot numbers.  I suppose I have some more reading to do.
Reply
#13
In response to your 1st post:

The Items are kept in memory. Where they reside at (the exact memory addresses) can vary, because it's in Dynamic memory.

Yes, I set the value that the game recognizes as green shell into r3. Then the original/default instruction of the hook address is next.

In the stw r3, 0x0020 (r23) instruction, the value in r23 (which is a dynamic memory address) is added with 0x0020. The result of this addition (which is known as the effective address) is the exact memory address of where the r3 value is written to.

The issue I think you're having is assuming this r23 + 0x0020 address is some sort of constant. It's not. The address number itself varies. This is why you CANNOT use something such as a 32-bit RAM Write code. You need an ASM code because the address in r23 will always vary. We need that value in r23 to know where to "write" the Item value.

In response to your 2nd post:

That was a clever idea! Good work. You will need some assembly though to get the 3rd goal completed.

----

Here's what I would do.

You will need the the Hook Address of Unnamed Code's. - https://mariokartwii.com/showthread.php?tid=1995

Let's say you use the PAL game. That would be 0x80791958. Simply launch your MKWii game in Dolphin, once you get to the main menu, pause the emulation. Go to the Address 0x80791958 in code view.

You should see this instruction:
lwz r31, 0x008C (r3) # This is loading some value from dynamic memory into r3.

Now let's view Unnamed's source to his code:
li r31, 0xYY ## Load the Item Number in r31
stw r31, 0x90 (r3) ## overwrite Item number in Inventory
li r31, 0xXX ## Load the Item in r31

Notice how he doesn't include the hook address's original instruction. Why? Well the original instruction is loading a value into r31. He doesn't need to "rewrite/restore" the value back to memory. He can simply just modify r31.

You will notice he modifies r31 twice. The first time he's using it as a scrap register to modify the contents of memory at r3 + 0x0090. This is where the Item Number is located at. Then he modifies r31 a second time. This changes the Item Value.

Item Value = what kind of Item
Item Number = how much of the Item

Since the original instruction loads the Item Value from r3 + 0x008C, we can conclude that....
Item Value is located at r3 + 0x008C
Item Number is located at r3 + 0x0090

What his code is doing is this..
1. Use r31 as a scrap register to write new Item Number
2. Write that new Item Number to memory
3. Place in new r31 for Item Value *instead* of loading a value into r31 from memory

---

What we need now is to see if any of the other non-volatile registers (r14 thru r30) are keeping the Slot of the Player. Set an Instruction BP on 0x80791958 and enter a normal Offline VS Race.

Every time you or the CPU uses an item it will trigger the Instruction BP. Every time it gets triggered, take note of r14 thru r30. After a handful of hits, you may see a pattern in one or a few registers. If you see a register that is always 0 when the BP hits for you *and* never 0 (1 thru B) when it the BP hits for the CPU, than that's the slot value. It's possible a register may not be used for a Slot Value. If that's the case, we can still get the Slot Value just by other means/methods.

Try that and let me know how it goes. Hopefully, some of this will make sense. I've just gotten out of the hospital so my mind may not be 100%.
Reply
#14
(03-12-2024, 09:13 PM)Vega Wrote: The issue I think you're having is assuming this r23 + 0x0020 address is some sort of constant. It's not. The address number itself varies.

Yes, this was absolutely a misconception on my part.  I get it now, the address is always different but the equation to find the address stays the same.

(03-12-2024, 09:13 PM)Vega Wrote: You should see this instruction:
lwz r31, 0x008C (r3) # This is loading some value from dynamic memory into r3.

Is it loading from dynamic memory into r3 or into r31?  I'm still new to this but I thought the destination register came first, which would mean it's loading from dynamic memory into r31.

(03-12-2024, 09:13 PM)Vega Wrote: Since the original instruction loads the Item Value from r3 + 0x008C, we can conclude that....
Item Value is located at r3 + 0x008C
Item Number is located at r3 + 0x0090

So, if I'm understanding you correctly, we need to write ASM code that will figure out what value is at r3 + 0x008C, and store it in a register.  I'm guessing this will look something like the default instruction: 
lwz r31, 0x008C (r3)
Unless...that part is already happening, because it's the default instruction?  But it doesn't seem to be, since r31 doesn't seem to ever contain anything that looks like the item codes listed on that page

Anyway, after we figure out how to store it in a register, we have to write from that register to static memory using a stw command.  That's where the exception vector area you mentioned will come in, because we can safely store values in that portion of memory.  Am I right so far?

---

In regards to the question at the end, it doesn't seem that breakpoint has any consistent numerical values stored in registers when the breakpoint is hit.  27 and 29 seem to be consistently changing when we hit that breakpoint, but the values look something like 81247ebc, and do not repeat each time P1 uses an item.

(03-12-2024, 09:13 PM)Vega Wrote: I've just gotten out of the hospital so my mind may not be 100%.

I'm very sorry to hear this.  I wish you all the best and a swift recovery!
Reply
#15
That was a typo my part.

lwz r31, 0x008C (r3) will load a word value into r31

You will need to write some ASM code to check whats at r3 + 0x008C.

You can have the original instruction execute for you first. That way you can simply run a check/comparison on what contents on in r31.

Then you write some code to write some flag/bool at a desired EVA Address. From there Dolphin logs can take care of that via a Memory BP log.

The reason why you aren't seeing item values in r31 is because you need to step thru the lwz instruction to see what gets loaded into r31. Whatever is there beforehand may be some previous pointer or junk value.

Regarding the slot stuff, I went and checked Unnamed's code myself, there are zero non-volatile registers that contain the slot.

Basically r27 or r29 may be a "base/master" pointer of sorts. If so, you can use r27 or r29 to do a series of pointer-level loading to get the slot. Stebler does this in the classic version of his pretty speedometer code. Basically various important information can always be grabbed if you have this pointer at your disposal.

Portion of code from Stebler's source:
# get the player index of the player on which the hooked function is working
lwz r3, 0x0 (r29)
lwz r3, 0x0 (r3)
lbz r3, 0x10 (r3)

I do this is my Hop Anywhere code - https://mariokartwii.com/showthread.php?tid=1966
#Get Slot function is hooked on
lwz r12, 0x0 (r29)
lwz r12, 0x0 (r12)
lbz r12, 0x10 (r12)

I'm not sure of the technical/proper name of this pointer or how to tell if this is the pointer in question, But you can try something like this...
lwz r3, 0x0 (r27)
lwz r3, 0x0 (r3)
lbz r3, 0x10 (r3)
or..
lwz r3, 0x0 (r29)
lwz r3, 0x0 (r3)
lbz r3, 0x10 (r3)

Maybe somebody can chime in on a diff/easier way.

By the way, r3 is safe to modify as long as you have the original instruction first in your source.

In conclusion your ASM source will this..
1. Original instruction
2. Check for Star, if item not Star, end code (write 0 flag to EVA)
3. Slot loading code
4. Is slot value 0 thru 3?
5. If yes, write 1 flag to EVA. if not write 0 flag to EVA
Reply
#16
Alright, so I understand most of this. Thanks so much for your help thus far.  My code will be at insertion address 0x8078894C (for NTSC-U):

(03-13-2024, 11:36 PM)Vega Wrote: 1. Original instruction

That's lwz r31, 0x008C (r3).  We got that from the code viewer.

(03-13-2024, 11:36 PM)Vega Wrote: 2. Check for Star, if item not Star, end code (write 0 flag to EVA)

This part I would have no idea how to do, I don't know how to do logic within ASM yet.  But at least I know that star = 09.

(03-13-2024, 11:36 PM)Vega Wrote: 3. Slot loading code

That will be either
lwz r3, 0x0 (r27)
lwz r3, 0x0 (r3)
lbz r3, 0x10 (r3)

or

lwz r3, 0x0 (r29)
lwz r3, 0x0 (r3)
lbz r3, 0x10 (r3)

(03-13-2024, 11:36 PM)Vega Wrote: 4. Is slot value 0 thru 3?

Yeah, same issue as #2 unfortunately...not sure how to do this.

(03-13-2024, 11:36 PM)Vega Wrote: 5. If yes, write 1 flag to EVA. if not write 0 flag to EVA

Well, once I get the logic parts down, I understand that you can write to the EVA like this:

lis r12, 0x8000 #Set the upper 16 bits of the EVA
stb rX, 0x164F (r12) #Store rX to the EVA at address 8000164F

So maybe that 0 or 1 would need to go in a register first?
Reply
#17
(03-14-2024, 07:47 AM)seanmcnally Wrote: This part I would have no idea how to do, I don't know how to do logic within ASM yet.  But at least I know that star = 09.

The assembly tutorial will teach you how to do basic comparisons.

(03-14-2024, 07:47 AM)seanmcnally Wrote: Yeah, same issue as #2 unfortunately...not sure how to do this.

That would also require basic comparisons.

(03-14-2024, 07:47 AM)seanmcnally Wrote: So maybe that 0 or 1 would need to go in a register first?

Yes.
Reply
#18
So, I've officially completed the Beginner ASM tutorial to a degree where I understood it 100%.  The video was very helpful, thanks for making that.

I've officially got my first working code!  While I do now understand how to do logic in ASM (branching), and will make a code implementing that logic later, I want to first show a code that just grabs and dumps the information.  Here's my source:

Insertion Address 0x8078894C (for NTSC-U, see here for ported codes)

Code:
lwz r31, 0x008C (r3) # Default instruction, loads item to r31

# Find out what item was used, store to 8000164F
lwz r31, 0x008C (r3) # Default instruction, loads item to r31
lis r12, 0x8000 #Set the upper 16 bits of the EVA
stb r31, 0x164F (r12) #Store what item was used to the EVA at address 8000164F

# Load the slot of player that just used an item, store to 8000165F
lwz r3, 0x0 (r27) # Slot loading code start, load mem address from r27 into r3
lwz r3, 0x0 (r3)  # Load new word from a memory address based on the word we just loaded
lbz r3, 0x10 (r3) # Load new byte from a memory address based on the word we just loaded
lis r12, 0x8000 #Set the upper 16 bits of the EVA
stb r3, 0x165F (r12) #Store who used an item to the EVA at address 8000165F

And the compiled code:
Code:
C278894C 00000005
83E3008C 83E3008C
3D808000 9BEC164F
807B0000 80630000
88630010 3D808000
986C165F 00000000

So, if I wanted to, I could just stop here and use Chataigne for the logic.  But, now that I CAN use ASM to do the logic, I might as well Wink  I'll work on that code next.

But, in the meantime, I wanted to stop here and ask a question.  I put memory write breakpoints at 8000164F and 8000165F, and for whatever reason according to Dolphin's log my code seems to be writing extra junk beyond the byte I assumed I was writing with my stb commands.  For example, when P1 uses a Fake Item Box, it logs:

Code:
17:48:916 Core\PowerPC\BreakPoints.cpp:381 N[MI]: MBP 80002354 ( --- ) Write8 80f2bf03 at 8000164f ( --- )
17:48:916 Core\PowerPC\BreakPoints.cpp:381 N[MI]: MBP 80002368 ( --- ) Write8 80e90300 at 8000165f ( --- )

This is the intended behavior if you only look at the last two written digits (03 for Fake Item Box, 00 for P1).  But what's the rest of it all about?  The 80f2bf and 80e903?  In DME's memory viewer, I'm not seeing any of those digits at that address.  It does not affect functionality in any way, I'm just curious.

edit: added insertion address
Reply
#19
Congratz on conjuring up your first source.

Some notes/tips:

I don't know if r27 is the "base" pointer for the portion of code for the slot loading. You will need to step by step your code and see if r3 (after the lbz) is always a number from 0 thru B. If not, then try r29. Tutorial for stepping - https://mariokartwii.com/showthread.php?tid=1383

And oh yeah, I totally forgot. Yes, youre right, you can just store both the Slot & Item to the EVA, instead of a flag. Nice catch.

You have the default instruction in your source twice, remove the 2nd one.

You also have "lis r12, 0x8000" twice. Not needed as r12's value remains intact by the time your code reaches the 2nd stb.

Regarding the weird dolphin logs. Write8 must mean 8-bits. Can't be 8 bytes because that's a double-word. Not sure about why those pointers are being listed. No idea tbh.
Reply
#20
(03-16-2024, 02:23 AM)Vega Wrote: I don't know if r27 is the "base" pointer for the portion of code for the slot loading. You will need to step by step your code and see if r3 (after the lbz) is always a number from 0 thru B. If not, then try r29. Tutorial for stepping - https://mariokartwii.com/showthread.php?tid=1383

I don't fully understand what a base pointer is, but I do know I tested it for all four human players and it works.  I'll come back to this if I run into issues, I appreciate the info

(03-16-2024, 02:23 AM)Vega Wrote: You have the default instruction in your source twice, remove the 2nd one.

You also have "lis r12, 0x8000" twice. Not needed as r12's value remains intact by the time your code reaches the 2nd stb.

Entirely my bad.  This is because I initially wrote this as two separate codes (get item used, get player that used item), and then just sort of mashed them together without thinking about it once they both worked Big Grin .  Here's the updated code:

C278894C 00000004
83E3008C 3D808000
9BEC164F 807B0000
80630000 88630010
986C165F 00000000

Source:
Instruction 8078894C
lwz r31, 0x008C (r3) # Default instruction, loads item to r31

# Find out what item was used, store to 8000164F
lis r12, 0x8000 #Set the upper 16 bits of the EVA
stb r31, 0x164F (r12) #Store what item was used to the EVA at address 8000164F

# Load the slot of player that just used an item, store to 8000165F
lwz r3, 0x0 (r27) # Slot loading code start, load mem address from r27 into r3
lwz r3, 0x0 (r3)  # Load new word from a memory address based on the word we just loaded
lbz r3, 0x10 (r3) # Load new byte from a memory address based on the word we just loaded
stb r3, 0x165F (r12) #Store who used an item to the EVA at address 8000165F
---
For anyone who wants to use this the way I am, add memory write breakpoints at 8000164F and 8000165F.  Choose "Write To Log".  Dolphin will write these item code values to 8000164F depending on what was used.  It will also write 0-3 based on what human player used the item.
P1 = 0
P2 = 1
P3 = 2
P4 = 3
Reply


Forum Jump:


Users browsing this thread: 6 Guest(s)