Jump to content
  • 0

MIPS beginner in need of help


Ideka
 Share

Question

Hey everyone!
Recently I decided to finally get my ass off and take on the huge task of learning r4300i disassembly. I have basically spent the last two weeks just trying to find documentation on the subject, and learn whatever I could from it. This, I hope anyways, has probably given me some decent knowledge in the very basics of MIPS disassembly.
 
A few days ago I started trying to write ASM hacks of my own (for the OoT MQ debug ROM). Obviously I wanted to start with something simple, namely that the current Rupee amount would increase by 1 each time that the D-pad up button was pressed. I used the source of
 as a base when (trying) to write the hack, which resulted in what I thought was a pretty legit-looking code. Of course it didn't work at all in-game. The closest result I managed to get was that the game paused each time that D-pad up was pressed, which is kinda cool but not very close to the desired effect.
 
I have tried to fix the problem by myself for a time now, but I just don't seem to have the knowledge to locate the problem. I suspect that some instruction might be missing, or that I may have constructed the hack in a weird way. Another, "sillier" possibility is that I've just assembled the gs code incorrectly, since I had to do it manually due to neither the Renegade64 nor Galatea assemblers working correctly on my computer. I haven't been able to find any of these issues though, and I have checked the gameshark code multiple times for faults I couldn't find. I think that the solution simply just lies beyond me and my current capabilities.
 
I hope that maybe some of our experienced and knowledgeable MIPS-disassemblers will show up and save the day, but any help would be mostly appreciated really. Anyway, here's the source and gs code:

 

Source:

 

.ORG 0x80047E50
J 0x801A0000
NOP


.ORG 0x801A0000
LUI T0, 0x8016 ; Loads upper adress to rupee amount in T0
LH T4, 0xE694(T0) ; Loads halfword from T0 into T4

LUI T0, 0x8016 ; Loads upper adress to controller buttons
LHU T2, 0x6AF0(T0) ; Loads unsigned half-word into T2 from T0(controller buttons)
ADDIU T3, R0, 0x0800 ; Dpad-up stored into T3
BEQL T2, T3, 0x801A001C ; If T2(controller buttons) equals to T3(Dpad-up pressed), branch to 0x811A001C
ADDIU T4, T4, 0x0001 ; Adds immediate value 0x0001 to T4(current rupee amount)

.ORG 0x801A001C
LUI T0, 8016 ; Loads upper adress to rupee amount
SH T4, 0xE694(T0) ; Stores new rupee amount(T4) into current rupee amount(T0)
J 0x80047e58
LH V0, 0xE690(V0) ; "this is what was replaced at 0x80047E50" (source: savestate)
SLTI AT, V0, 0x0011 ; "if taken out it would cause a lot of trouble" (source: savestate)

NOTES:
0x8015E694 = Rupee amount

GS code (assembled by hand, may be incorrect):

81047E50 0806
81047E52 8000
81047E54 0000
81047E56 0000
811A0000 3C08
811A0002 8016
811A0004 850C
811A0006 E694
811A0008 3C08
811A000A 8016
811A000C 950A
811A000E 6AF0
811A0010 240B
811A0012 0800
811A0014 516A
811A0016 8006
811A0018 258C
811A001A 0001
811A001C 3C08
811A001E 8016
811A0020 A50C
811A0022 E694
811A0034 0801
811A0036 1F96
811A0038 8442
811A003A E690
811A003C 2841
811A003E 0011

 
And again: any help would really mean a lot to me! Thanks for reading!
Link to comment
Share on other sites

9 answers to this question

Recommended Posts

  • 0

Thoughts:

  • Not confident about the place where you're grabbing the D-Pad input (0x80166AF0). Assuming it's the same as NTSC 1.0, that bit of ram should be part of some stack. The title screen reset code grabbed input from the Global Context (it's not documented yet, but input for all 4 controllers should be in the 0x54 range).
  • Is 801A0000 really a safe spot to inject your code?
  • Your source code isn't preserving the state of your registers by pushing the register values on the stack/popping them off when you're done. Are you sure it's ok to re-assign their values within this context?
  • You should be able to save an instruction by not assigning T0 to the same value later on in the source, two if you decide not to change the spot that you're reading input from
Link to comment
Share on other sites

  • 0

 

Thoughts:

  • Not confident about the place where you're grabbing the D-Pad input (0x80166AF0). Assuming it's the same as NTSC 1.0, that bit of ram should be part of some stack. The title screen reset code grabbed input from the Global Context (it's not documented yet, but input for all 4 controllers should be in the 0x54 range).
  • Is 801A0000 really a safe spot to inject your code?
  • Your source code isn't preserving the state of your registers by pushing the register values on the stack/popping them off when you're done. Are you sure it's ok to re-assign their values within this context?
  • You should be able to save an instruction by not assigning T0 to the same value later on in the source, two if you decide not to change the spot that you're reading input from

 

 

I'm not sure about the placement of the stack in memory, but what I did to get input was decode the GS code for 'press L to levitate' and observe the changes in the states of the nearby bits when buttons were pressed by placing a watchpoint on the address that the GS code used.

 

For one of the OoT roms (probably 1.0), I typically loaded my stuff starting around $80170000, so it should be safe to load at $801A0000 I think.

 

Unless he has his hook at the wrong place, there's no need to preserve T* registers, they're temporary.

 

 

The problem I see is that he's simply jumping to $801A0000, and the stub he has loaded there doesn't hang or jump/branch to anywhere else. He should be jumping to 'RA' at the end of his stub.

 

 

I'd highly suggest using Renegade64 to compile your GS code. There's several versions of it, but the best one to use imo is the one that shows a splash screen of a shark when it starts up.

Link to comment
Share on other sites

  • 0

First off, this contains a lot of useful general RAM addresses and the structure of certain data within memory: http://spinout182.com/god/zelda64.h

 

Let me make a couple of comments about your hack:

  • 0x80166AF0 is indeed one of the many valid controller data addresses so no need to worry about that.
  • You are checking for to see if only D-pad up is pressed. You might want to AND the value in T2 with 0x0800 in order to check the bit.
  • mzxrules made a very good point when he said that you may be corrupting all the registers because of the place that you have hooked into; try hooking into a function at the very end (temporary registers are no longer needed by this point) by replacing a jr ra to a jump to your code.
  • SoulOfDeity may also be correct when he says the memory where you've placed your code may be invalid... Have you tried a different spot like 0x80600000? From 0x806000000 on is free RAM space till 0x80800000.
If it were me writing your hack, I would have written it like this (Renegade style)... 

.ORG 801064B0 ; This is the function return from WriteDCacheBackAll, if I remember correctly... this runs every frame
J 80600000 ; Jump to our hack

.ORG 80600000 ; Free space in RAM!
LUI T0, 8016
LH T0, E694(T0) ; Load rupee amount
LUI T2, 8016
LHU T2, 6AF0(T2) ; Load controller button input
ANDI T2, T2, 0800 ; Grab the bit corresponding to D-pad up to see if it is pressed; if it is then T2 will be nonzero
BNEL T2, R0, Exit ; If D-pad up is pressed then execute the delay slot before jumping to Exit 
ADDIU T0, T0, 0001 ; { Delay slot: increment rupee amount (only executed if the above statement is true) }

Exit:
LUI T2, 8016
JR RA ; Return (this will execute the delay slot (the instruction immediately below) before returning)
SH T0, E694(T2) ; Delay slot: Store potentially new rupee amount
GS code:

 

811064B0 0818

811064B2 0000

81600000 3C08

81600002 8016

81600004 8508

81600006 E694

81600008 3C0A

8160000A 8016

8160000C 954A

8160000E 6AF0

81600010 314A

81600012 0800

81600014 540A

81600016 0001

81600018 2508

8160001A 0001

8160001C 3C0A

8160001E 8016

81600020 03E0

81600022 0008

81600024 A548

81600026 E694

 

 

 

Also, you should try using Galatea to assemble your hacks. It worked fine for me on Windows Vista, 8, and 8.1. However, most other debugging tools that it includes do not work such as hooking in emulator process memory.

 

This might be a good reference for encoding instructions but I haven't looked over it too much. It seems to be accurate when encoding JAL instructions at the very least: http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html

 

If you wanna try to use Galatea to compile/assemble your hacks, make sure your assembly follows GNU syntax. Take a look at this hack I made as an example of how to write it: http://www.cs.utexas.edu/~jason777/Modding/Zelda%2064/Fire_Sword/Galatea_FireHack.S

 

EDIT: Updated the small rewrite I did to be assembled by Renegade64.

Link to comment
Share on other sites

  • 0

If you wanna try to use Galatea to compile/assemble your hacks, make sure your assembly follows GNU syntax. Take a look at this hack I made as an example of how to write it: http://www.cs.utexas.edu/~jason777/Modding/Zelda%2064/Fire_Sword/Galatea_FireHack.S

 

This is why I suggested Renegade64 (it uses standard MIPS syntax with register mnemonics, as opposed to GCC's goofy and quirky syntax). Plus it generates GS code directly, including in the format Nemu64 uses. Although, if you use Galatea (or any ide supporting a mips configured GCC), you have the advantage of being able to use linker scripts to do most of your hacks in C.

  • Like 1
Link to comment
Share on other sites

  • 0

For some reason, comdlg32.ocx that Renegade came packaged with was considered a missing dependency and would terminate the application. I ended up using Galatea and got used to it. I did end up resolving the issue with Renegade, but I had already grown fond of Galatea by that point.

Link to comment
Share on other sites

  • 0

Wow, thanks so much everybody! I didn't expect to get these many replies, it's very appreciated. I'll look into all of these things soon. I had heard that $801A0000 was freespace, but I'll be sure to try with $80600000 as well. Also I got the Renegade assembler working,  which should help me greatly. Again, thanks!

Link to comment
Share on other sites

  • 0

Wow, thanks so much everybody! I didn't expect to get these many replies, it's very appreciated. I'll look into all of these things soon. I had heard that $801A0000 was freespace, but I'll be sure to try with $80600000 as well. Also I got the Renegade assembler working,  which should help me greatly. Again, thanks!

 

No problem. In case you want to try it out, I'll give you a quick example of how to write a C hack:

  • Create a new file for your C-code called 'stub.c'
void mystub (void)
{
}
  • Create a new linker script called 'stub.x'
ENTRY(mystub)
SECTIONS
{
  . = 0x806000000;

  .text :
  {
    *(.text)
  }

  .rodata :
  {
    *(.rodata)
  }

  .data :
  {
    *(.data)
  }

  .bss :
  {
    *(COMMON)
    *(.bss)
  }
}
  • Compile your code like `gcc -o stub -EB -mabi=32 -march=vr4300 -mtune=vr4300 -Wl,-T,stub.x,--oformat,binary,--emit-relocs stub.c`

     

    This will create a binary file called 'stub' containing your stub (as opposed to an elf file) You can either turn it into a gameshark code, or you can inject it into the rom itself and manually DMA it into memory (which is what I prefer to do)

You should still be able to use your hook without any issues. Forewarning, I wrote this tutorial off the top of my head without testing it, but I'm fairly sure it'll work. At least, with the exception of '--emit-relocs' as binary format doesn't play nicely I think.
  • Like 1
Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.