Copy Link
Add to Bookmark

How to make a Nintendo 64 Trainer

Nintendo64's profile picture
Published in 
N64 various
 · 28 Aug 2019
Nintendo 64 Trainer from Crazy Nation.
Pin it
Nintendo 64 Trainer from Crazy Nation.

How to make a N64 Trainer

Ladies and gentleman,

Welcome to my "How to make a N64-Trainer" documentation.

The reason why i did this doc is very simple: i am quitting all my activities in the "n64-scene" for many reasons, i think you don't care for so i won't go into that any further. Furthermore it would be nice to see more groups doing trainers. So i hope this will help some dudes to start!

So however, let's come to the real documentation.

First i want to explain how my trainers are working.. I think you all know the hardware game-enhancers like "Action Replay", "Gameshark", "Gamebuster" and so on... with this hardware stuff you can enter codes like this e.g.:

8003567C 0067

If the answer is YES, then i will explain you what the fuck this codes mean.


8003567C 0067 <-- Value to be written
~~~~~~~~ ****
Memorylocation in N64 RAM

If you enter such a code the Gameshark hardware or whatever will do the following: It updates the MEMORYLOCATION with the VALUE very often (don't know exactly how often in a second but this doesn't matter now! :-) )

And exactly this is how my trainers work. So in a strictly definition my trainers are no REAL trainers, like i did them on e.g. the Amiga. On Amiga for example it was better to find the ROUTINE in the GAMECODE which was responsible for subtracting your Lives or Health etc.. and once you found this routine, you had the possibility to kill it with a NOP or something..

On the Nintendo 64 you can say its emulating a Gameshark. Unfortunately I must do it like this way but the fact is that i just don't have this much possiblities with hard and software like on my good old Amiga ;) NMI-shit and stuff..

But the result is the same so... its not a clean way but it works also.

So basically what we have to do is emulate a Gameshark and this is very easy!:

1. We need a routine which is called VERY OFTEN to replace VALUES in N64-MEMORY while the user is playing the game.

Okay, if you still know what i am talking about, CONTINUE READING! If you don't know what i am talking about, QUIT READING NOW:)

So first step:


We must try to find a routine in the GAMEROM which is called very often.. here we can hook up our own UPDATE-CODE which will do the rest (=the "trainer" itself).

Personally i use "OsViSwap" but you also can use "WriteBackDCacheAll" , or "__osRestoreInt" ... i just tested my trainers with the above mentioned three functions and it works perfectly.

To find this routines get the tool "LFE" from (LFE = [Libary-Function-Extractor] (c) Ravemax of Dextrose)

Then get the library "libultra.lib" from the PSY-Q-N64-Devkit..

Swap your gamerom now to Z64/CD64 format and make a backup of the rom... now RESIZE the ROM to 8 Megabit and use LFE to find out where the functions are in the ROM.

The commandline for this is:

LFE.EXE [ROM.Z64] libultra.lib

This will take a while now.. - then LFE gives you back a ".COD" file!

Here i included such a .COD file just for example:

[============BEGIN TEST.COD==============]
0x8005e980,osWritebackDCacheAll <--- THIS ONE MAYBE
0x80066170,__osRestoreInt <--- THIS ONE MAYBE, TOO
[=============END TEST.COD===============]

So now search for one of the above mentioned functions. Hmm... in this game we don't have a OSViSwap.. so we could use the "osWritebackDCacheAll" -Function for our example.

Now take the resized 8-Mbit-ROM again and disassemble it with N64PSX by NAGRA! (get it from or

The command line will look like this:

N64PSX.EXE -n64 [ROM.Z64] >ROM.ASM

This nice tool will use the .COD file created by LFE and will mix it together with the disassembled code so you can exactly see where the functions begin.. my example will bring ROM.ASM as a result.

Now, open "ROM.ASM" in your favorite editor and search for the function we want to use ( "osWritebackDCacheAll" ).

[============BEGIN ROM.ASM==============]
8005e974: 00000000 .... nop
8005e978: 00000000 .... nop
8005e97c: 00000000 .... nop
8005e980: 3c088000 <... lui $t0,32768 ; osWritebackDCacheAll
8005e984: 240a2000 $. . li $t2,0x2000
8005e988: 010a4821 ..H! addu $t1,$t0,$t2
8005e98c: 2529fff0 %).. addiu $t1,$t1,0xfffffff0
8005e990: bd010000 .... cache 0x1,0x0000($t0)
8005e994: 0109082b ...+ sltu $at,$t0,$t1
8005e998: 1420fffd . .. bnez $at,0x8005e990
8005e99c: 25080010 %... addiu $t0,$t0,0x0010
8005e9a0: 03e00008 .... jr $ra <--THIS IS THE END OF THE FUNCTION!
8005e9a4: 00000000 .... nop
8005e9a8: 00000000 .... nop
[=============END ROM.ASM===============]

Now, we must search for the end of the function, this must be a "jr $ra" . Once you found it, keep the memory-address where it is located (In our example its: $8005e9a0). At this address we will hook up our trainer-routine. Let's move to the next chapter!


Okay, here we go with the main-routine which is responsible for updating the values in the Nintendo 64 RAM!

This routine is very simple.

Just Imagine you got a Gameshark-Code like this:

8003567F 0064

As i said above this means for the Gameshark nothing else than:

So here a neat code which will do this for us in ASSEMBLER and this will be the code which will be hooked to the Function we found before, to go sure our routine will be executed every time the function osWriteBackDCacheAll is called.

sub sp,28 ;Get som Stackspace
sw s0,0(sp) ;Better save this regs
sw t0,4(sp) ;coz our routine below
sw t1,8(sp) ;will trash them!
sw t2,12(sp) ;t1 and t2 is for additional stuff

li t0,$8003567F ;Memory-Address
li s0,$64 ;Value
sb s0,(t0) ;Write it into Memory.

lw s0,0(sp) ;Okay.. lets restore the
lw t0,4(sp) ;regs..!
lw t1,8(sp)
lw t2,12(sp)
add sp,28 ;Free our Stackspace!
jr ra ;This will jump back
nop ;to osWriteBackDCacheAll!

That's IT!


Above we just coded our trainer-routine. But now we must attach this routine to the "osWritebackDCacheAll" -Function we found in the gamerom in order to get the trainer working.

This is a very simple routine, too so take a look at the following ASM code:

org $BXXXXXXX ;Orged in ROM see explanation

la t0,patchstart ;patchstart
li t1,$A0000200 ;This is place our Trainerroutine
;will stay
la t2,patchend-patchstart+4 ;Lenght to copy
lw t3,(t0) ;this loop will copy our
sw t3,(t1) ;patchroutine to $A0000200
add t0,t0,4 ;so easy.
add t1,t1,4
bne t2,zero,loop
sub t2,t2,4

li t0,$A005E9A0 ; our osWritebackDCacheAll function!!

li t1,$3c088000 ; Patch the function
sw t1,(t0)
li t1,$35080200 ; Patch the function
sw t1,4(t0)
li t1,$01000008
sw t1,8(t0)

li ra,$b0000008 ;This is the universial backjump
lw ra,(ra) ;routine.. explanation follows.
add ra,ra,$10
jr ra ;Back to the game!!

;here is the patchroutine (see above) :)

Okay, what does this routine now?

First of all i have to say something about the "org" . Before you assemble this little loader you must search in the Gamerom for a nice unused place. Take your favorite hex-editor and load up your gamerom again and take a look.. - if you found free space at e.g. $7FC000 in the rom and want to place your loader there, you have to ORG it to $B07FC000.

Then our neat code will copy our "Trainer routine" (patch start) to a safe memory-location. (its $A0000200)

After that it will patch the routine located at $A005E9A0. Yeees, you are right.. this $A005E9A0 is our osWritebackDCacheAll, we found some chapters ago! but be sure to replace the "8" with an "A" . (We found $8005E9A0 and we will patch $A005E9A0)!!!

Yeah, all done!, our trainer routine is in a safe-memory location where it can operate from, the osWritebackDCacheAll points now to our trainer-routine, so it will be called every time the Function is called.

So we can jump back to Gamecode: I have made a nice routine, which will do it universal, so no need to change something for every game.


So.. finally we made it! we have the Trainer. The only thing you have to do now is to patch the ROM-Start at $1000, save the orig-code from this location, jump to your loader routine ($B07FC000) and before you jump back, execute the orig-code you saved from $1000. And OF COZ, doing a nice trainermenu in Assembler (get Titaniks excellent sources from or get my trainermenu-source at, too) Thats it.. get movin'!!!!!!!!!!

I hope i helped you with this document a little bit. Maybe this method will be nonsense, if new hardware appears, where you can set Breakpoints and other usefull stuff.. But in this current point of time i think its a good way to do trainers.. - not the best way... but WORKS :)

All infos, n64-sources etc can be obtained from, too.

To make trainers is an ART not a RACE! :D

Signed, Icarus of Paradox/Lightforce/Crystal/TRSi/Vision/LSD/Hellfire

AUGUST - 1999!

Greetings to all my friends in the scene.. stay cool.
To all the others... FUCK OFF!

← previous
next →
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.