Post subject: Keeping track of game routines
Player (198)
Joined: 12/3/2006
Posts: 151
I was wondering if there was an easy way to keep track of the number of times a certain game routine was run by the emulator. In my case I'm trying to keep track of the number of times the RNG is called. I've tried adding some ASM code to the rom which would increment a value stored in the game's RAM, but I couldn't find any 'free space' to paste it in. I'm no programmer so I wouldn't know how to do it, but shouldn't it be possible to alter the emulator to add this functionality?
Player (80)
Joined: 3/11/2005
Posts: 352
Location: Oregon
You could do this easily enough by watching the CPU's PC for the address of the RNG after each instruction. Alternately, you could watch the RNG's seed in RAM and note when it changes. Edit: I forgot to mention that doing this by modifying the emulator is a better (and probably easier) idea.
ideamagnate| .seen aqfaq <nothing happens> DK64_MASTER| .seen nesvideoagent * DK64_MASTER slaps forehead
Post subject: Re: Keeping track of game routines
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Adding the ASM code in the ROM would affect timings, and possibly randomness as the result too. It is fairly easy to add such function in an emulator. I have done it couple of times on FCEU. Unfortunately I have no general solution; I have always customized it for the particular situation.
Player (198)
Joined: 12/3/2006
Posts: 151
$80/82AA 20 2D 83    JSR $832D
That's (in this particular game) the specific ASM line which jumps to the subroutine which generates the random numbers. I can already count the number of times this line is executed by setting breakpoints in Geiger's snes9x debugger, but it's lots of work so I'd like to automate it. I don't want to sound demanding/annoying, but I actually have no idea how to modify an emulator at all. If it isn't too much work it would be really neat if someone could add this to snes9x.
Player (198)
Joined: 12/3/2006
Posts: 151
Yay, I managed to hack an internal counter in the ROM to keep track of the RNG activity. I have succesfully played back my current Lufia 2 TAS with the hacked ROM, so it's safe to say the change doesn't affect timing and/or randomness. Thanks for your advice regardless :) Edit: Okay, I may have lied a tiny bit. I didn't have time to test the entire movie yesterday, and it turns out the movie does desynchronise after an hour. After expanding the counter to 2 bytes, and adding a proper initialiser, the movie desyncs after 5 minutes. I guess I'll have to make a test movie first using the hacked ROM (mainly for 'planning' luck manipulation) and when I'm done I'll have to remake the entire thing on the original ROM to make it sync and perhaps make it a couple of frames faster :p.
Former player
Joined: 3/23/2006
Posts: 211
I could probably hack this into snes9x for you if you can find the source code for whichever version of snes9x you use. It would help if you're using it on linux - I don't know how to compile Windows snes9x.
do not forget to *ENJOY THE SAUCE*
Player (198)
Joined: 12/3/2006
Posts: 151
I'm afraid I'm using it in Windows. However, I just realised if the counter was built in the emulator itself, it wouldn't save the counter when making a savestate, would it?
Former player
Joined: 3/23/2006
Posts: 211
Gunty wrote:
I'm afraid I'm using it in Windows.
Well, I'd need to find some of Nitsuja's instructions :-/
Gunty wrote:
However, I just realised if the counter was built in the emulator itself, it wouldn't save the counter when making a savestate, would it?
Nope, but snes9x could be made to store it in a text file accompanying the savestate by altering the "save" and "load" functions.
do not forget to *ENJOY THE SAUCE*
Player (198)
Joined: 12/3/2006
Posts: 151
Two and a half months later... I finally figured out how to compile the snes9x 1.51 source for Windows. Now, all that's left to do is modifying the source and recompiling it. However, as stated before, I'm not really a programmer, so the only thing I was able to do so far is introducing a global variable containing the number of times the game routine is called by the ROM. The things remaining are:
  • Detecting when the game executes the routine
  • Saving the variable when a savestate is made
  • Loading the variable when a savestate is loading
Since I kinda enjoy self-learning, I wouldn't mind (or even enjoy it) if someone familiar with the snes9x source could give me some pointers on how to implement the mentioned functions instead of doing all the coding for me.
Former player
Joined: 3/23/2006
Posts: 211
Gunty wrote:
  • Saving the variable when a savestate is made
  • Loading the variable when a savestate is loading
Try adding code to write it out to a text file or something at the top of bool8 S9xFreezeGame (const char *filename) and to load it in from the file in bool8 S9xUnfreezeGame (const char *filename) in snapshot.cpp
do not forget to *ENJOY THE SAUCE*
Player (198)
Joined: 12/3/2006
Posts: 151
Huffers wrote:
Try adding code to write it out to a text file or something at the top of bool8 S9xFreezeGame (const char *filename) and to load it in from the file in bool8 S9xUnfreezeGame (const char *filename) in snapshot.cpp
Alright, that's done. Now all that's left is detecting when the routine is run. Since the starting address of the subroutine is $80:832D, I figured the following code should increment the counter by one whenever the subroutine is run:
		if(Registers.PB==128 && Registers.PCw==33581)
		{
			SNESGameFixes.LufiaRNGCounter+=1;
		}
Where "Registers.PB" holds the Bank and "Registers.PCw" the address. I inserted it in the function "void S9xMainLoop (void)" in "cpuexec.cpp", but unfortunately it doesn't work. Any idea how to make this work?
Former player
Joined: 3/23/2006
Posts: 211
Gunty wrote:
I inserted it in the function "void S9xMainLoop (void)" in "cpuexec.cpp", but unfortunately it doesn't work. Any idea how to make this work?
That sounds like you put it in the right place to me (though I'm no snes9x expert), I don't know why it wouldn't work. I usually litter the bit of code in question with printf statements to check that the code gets run, and the variables I care about all contain sane values. Or you could try using a debugger to place a breakpoint on/near/in your code and see what happens if you execute it a line at a time - I don't know how to do this in C though.
do not forget to *ENJOY THE SAUCE*
Player (198)
Joined: 12/3/2006
Posts: 151
Ok, it's working fine now. Final question: how come the compiled program's size is 4.05 MB (or sometimes, randomly, even 7+ MB) whereas the official emulator is only 568 kB? Edit: Nevermind, I noticed I was using the "debug" configuration for compiling which doesn't compress the compiled program.