Extreme G walkthrough assumes you've read the Killer Instinct Gold walkthrough. again I'll be using the GoosN64 US version of the ROM 1. make a save state in PJ64 when the game is at the "copyright info" screen 2. open said save state in IDA, wait 3. what we're going to do first here is trace out the threads, so locate osCreateThread and put the appropriate trap in PJ64 to track it: if (PROGRAM_COUNTER==0x8007E550) DisplayError("thread=%08x",GPR[6].UW[0]); I get the following threads, analyze them in IDA. 8004dcec: Thread1 800897a8: Thread2 80091090: Thread3 8004de78: Thread4 8004ddfc: Thread5 800524e8: Thread6 8005c2e4: Thread7 800750a8: Thread8 4. ok, now we'll look at the calls to alCSeqNew. if (PROGRAM_COUNTER==0x800808BC) DisplayError("alCSeqNew ra=%08x",GPR[31].UW[0]); ra=800593bc in a fcn starting at 800592E8, I call it MusicStuff The area surrounding the alCSeqNew call is clearly all for loading the sequence, from the osPiStartDma to the alSeqpSetSeq and alSeqpPlay). Where does the address in ROM for osPiStartDma come from? osPiStartDma prototype is: s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, u32 devAddr, void *vAddr, u32 nbytes, OSMesgQueue *mq); devAddr is the ROM address, passed in a3. a3 is copied from s1 at 80059384 and s1 is loaded from a table entry indexed by v1 at 80059350. v1 is calculated from a base *((void*)0x8015B490) (loaded at 80059334, most likely the start of the seq table) and v0, which is dword_80095D2C*8. dword_80095D2C is our song number (as it is the reference into the sequence table). We must find where it is set from. Let's call it SongNum for ease of reference. We'll trace writes to this address via the r4300i_SW_VAddr function in memory.c, which is called for word-sized memory writes by the interpreter. add this line in there: if (VAddr==0x80095D2C) DisplayError("SongNum writted with %08x at %08x",Value,PROGRAM_COUNTER); We see that the first write is 0xffffffff (-1) from 0x800591d0. This is the game starting the sequence player off with nothing, there is probably a trap to make sure -1 isn't actually used. We might be able to use this, if everything is properly set up when this is written we might be able to start the game off playing any song we want instead of silence, then we can stop it very early on in execution. Let's look at 0x800591d0. This seems to be part of the fcn at 800591C0, which doesn't seem to be a song select function of any description. It's probably only ever used for this writing of song number -1. Let's try to talk it into playing something else, song 1 for example. Put this line in ExecuteInterpreterOpcode: if (PROGRAM_COUNTER==0x800591CC) GPR[3].UW[0]=1; GPR[3] is v1, the #3 General Purpose Register. Yes, we see that replacing v1 with 1 causes a song to play at the intro (the acclaim copyright screen) instead of silence. The only problem (and it's a minor one) is that PJ64 USF, in it's current state, will plug the song value into a0, not v1. Let's change the "sw $v1, SongNum" instruction at 800591CC to "sw $a0,SongNum". You'll notice that the next instruction isn't until 800591D4, indicating that "sw $v1, SongNum" is actually 8 bytes rather than the standard 4 for a MIPS instruction. IDA has combined two instructions, probably something like: lui $1,0x8009 sw $v1,0x5d2c($1) into a single functional unit. We'll be replacing both (though the first doesn't really need to change). Let me pull out my MIPS R4000 user's manual and see what needs doing: lui $1,0x8009 assembles to 3C018009 sw $a1,0x5d2c($1) assembles to AC245D2C so we'll write the following: if (PROGRAM_COUNTER==0x800591C0) { GPR[4].UW[0]=1; ((DWORD*)N64MEM)[0x591cc/4]=0x3C018009; // read song from a0, not v1 ((DWORD*)N64MEM)[0x591d0/4]=0xAC245D2C; // " } That seems to work (make sure you disable that bit in memory.c, we don't need to see it anymore). 5. now we'll try to cut things down to music when we hit that function I'll let you know in advance that cutting out any of the threads won't do it without killing the music as well. We'll try what we did with KIG, eliminating the osSendMesg after osViSwapBuffer so that the graphics code and overall game logic will freeze. Unfortunately we don't have any xrers to osViSwapBuffer in the explored code yet, so we'll have to locate it with PJ64. if (PROGRAM_COUNTER==0x80089F20) DisplayError("ra=%08x",GPR[31].UW[0]); we get ra=0x800543d0, which leads us to the call at 800543C8, and there is a jump to an osSendMesg further down right after osViBlack, which blacks out the screen after the switch. osSendMesg is at 80054570, let's eliminate that. if (PROGRAM_COUNTER==0x800591C0) { GPR[4].UW[0]=1; ((DWORD*)N64MEM)[0x591cc/4]=0x3C018009; // read song from a0, not v1 ((DWORD*)N64MEM)[0x591d0/4]=0xAC245D2C; // " ((DWORD*)N64MEM)[0x54570/4]=0; // eliminate gfx mesg } We see that it runs the music and halts game progress just as we want. Runs nice and fast, too. So we add a bit to make our save state: if (PROGRAM_COUNTER==0x800591C0) { GPR[4].UW[0]=1; ((DWORD*)N64MEM)[0x591cc/4]=0x3C018009; // read song from a0, not v1 ((DWORD*)N64MEM)[0x591d0/4]=0xAC245D2C; // " ((DWORD*)N64MEM)[0x54570/4]=0; // eliminate gfx mesg sprintf(SaveAsFileName,"XG_USF"); Machine_SaveState(); } and then we can run everything through PJ64 USF. params: Using this savestate: C:\XG_USF.pj Trace begin offset: 800591C8 (two instructions after start of fcn) Sparse output directory: C:\ Song values: 0 to f (by process of elimination) Spend 2000 alists ripping each song (to be on the save side, techno tends to repeat for a while before new bits come in, and even this may not be enough) To comment for a moment, this method (eliminating that osSendMesg call, that I used here, in KIG, and in XG2) is very nice and seems to produce very fast rips with little effort searching for things to eliminate. I shall use it more in the future. I finished with a 476 KB usflib and 16 miniUSFs totalling 972 bytes.