How to find ROM addresses and Game Genie codes with Gens Tracer

Tony Hedstrom
Written by: Tony Hedstrom 

[email protected]

http://www.angelfire.com/games2/codehut/

Version 0.4 6/05/07


This guide will show you how to find useful ROM addresses
and make Game Genie codes using a program called Gens
Tracer. I'll explain how to make and use memory traces
and assembly trace logs.

I originally wrote this for some people in a NHL 94 forum.


-------------------------------------------------

Here's a list of what you'll need...


1) Gens Hacking Version (http://thegshi.org/ (download
section)).

2) Gens Tracer (http://thegshi.org/ (download section)).

3) A hex editor (your choice or bpsoft.com for free trial
version).

4) NHL94 ROM (in bin format).

5) Some basic 68000 assembly language knowledge is
helpful, but not absolutely necessary.


Here's what that stuff is for...

We'll use Gens Hacking Version to find RAM addresses.
Some people use Kega Fusion to find RAM addresses. If
you'd rather use it, that's fine. We'll use Gens Tracer
for memory traces and assembly trace logs. Gens Tracer
is really the "magic" program that helps us find useful
ROM addresses. The hex editor is for finding ROM
addresses, and the NHL94 ROM is what we'll be poking
around in trying to find ROM addresses.


To try to keep this relatively simple, we'll find the
ROM address that determines how much time you get for
each period. The game normally lets you select from
5, 10 and 20 minute periods, and there is the "cheat"
that lets you have 30 second periods. I'll show you
how to find those values in the ROM so you can change
them to any value you want, and I'll show you how to
stop the clock completely so you'll have infinite time.
Not that you'd want infinite time, but mainly to show
you how it's done.

Since making Game Genie codes is kinda my "thing", I'll
also show you how to make Game Genie codes for all this
stuff.


Okay, lets get to the good stuff...

The first thing we need to do is find the RAM address
for the clock. This is very easy to do. Just start
up Gens Hacking Version, load your NHL94 ROM, and start
a game. When the clock starts to count down, click on
"Cheats / Search GG codes". Click the "reset" button
and then click "OK". Let the clock count down 1 or 2
seconds and click on "Cheats / Search GG codes". Now
make sure "less than", "Previous Value" and "1 byte"
are all checked, then click on "Search". Click "OK"
and go back to the game and let the clock count down
a few more seconds. click on "Cheats / Search GG codes"
again and click "Search". Keep repeating this until
you only have a few RAM addresses left. If you're
doing this on your own, you'll need to test each RAM
address to find out which one is the one you're looking
for. You can do that by highlighting the RAM address
and clicking "add cheat" and testing each one until
you find the one that you're looking for. For this
example, I'll tell you that the RAM address for the
clock is FFC469. It's actually FFC468, but for our
purposes (and to keep this shorter), FFC469 will work
fine.

Okay, so we know that the RAM address for the clock
is FFC469. Now we need to find out where in the ROM
this RAM address is being loaded, modified, etc.
That's where Gens Tracer come in.

When you set up Gens Tracer, it has a folder called
"tracer". In that folder is a text file called
"hook_log.txt". Open up that text file (with notepad)
and change it so it looks exactly like this...

hook_pc1 0 -1 -1
hook_pc2 1 -1 -1
hook_pc3 1 -1 -1

hook_rd1 0 -1 -1
hook_rd2 0 -1 -1
hook_rd3 0 -1 -1

hook_wr1 0 ffc469 ffc469
hook_wr2 0 -1 -1
hook_wr3 0 -1 -1

hook_ppu1 1 -1 -1
hook_ppu2 1 -1 -1
hook_ppu3 1 -1 -1

(There's other stuff down here, but just leave it as is).



As you can see, we put our RAM address for the clock
in there for a hook on write (hook_wr1). What this
does is tells Gens Tracer to make a note every time
that RAM address is changed, and what ROM address
caused it to change. This is similiar to breakpoints.

Save the changes you made to your "hook_log.txt" file
and close it.

Open up Gens Tracer, and load your NHL94 ROM. As soon
as you see the "NHL Hockey 94" title screen, press the
"," key on your keyboard. This starts the memory
tracer. Now keep pressing the "Start" button (usually
the "Enter/Return" key on your keyboard) until the
game starts. Wait until the clock counts down about
3 or 4 seconds and press the "," key again. This
stops the memory tracer. Exit Gens Tracer.

The memory trace that you just made for RAM address
FFC469 has been saved to a text file called "hook.txt".
When you open up "hook.txt", this is what you should
see...

[01:730A] W32 = 00000000 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[01:5DFC] W16 = 0257 [FFC468]
[01:5DFC] W16 = 0256 [FFC468]
[01:5DFC] W16 = 0255 [FFC468]
[01:5DFC] W16 = 0254 [FFC468]

TRACE STOPPED


There's some very useful info in this file. A quick
breakdown: The ROM addresses are on the far left side,
followed by how many bits, followed by the value, and
then the RAM address at the far right side.

The ROM addresses listed are not the exact ROM addresses
we're looking for, but they're usually pretty close.
Next I'll show you how to use the info in the "hook.txt"
file to find the ROM addresses we're looking for.


Here's the memory trace we just made:

[01:730A] W32 = 00000000 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[01:5DFC] W16 = 0257 [FFC468]
[01:5DFC] W16 = 0256 [FFC468]
[01:5DFC] W16 = 0255 [FFC468]
[01:5DFC] W16 = 0254 [FFC468]

TRACE STOPPED


Here's what each of those lines mean...

[01:730A] W32 = 00000000 [FFC468]
This one just sets the value to 00000000. nothing we need.

[00:7830] W16 = 0258 [FFC468]
This one tells us which ROM address moves the value 0258
to our RAM address for the clock. 0258 is a hex number.
0258 = 600 in decimal. There are 60 seconds in a minute,
so 600 divided by 60 = 10 minutes. 10 minutes is the
amount of time that is on the clock when the game started.
We can use the ROM address in this line to help us find
the actual ROM address we're looking for (the ROM address
to change the amount of time you start the game with).

[01:5DFC] W16 = 0257 [FFC468]
This one tells us the ROM address that is subtracting one
number from the clock value for every second that goes by.
We can use this ROM address to help us find the instruction
that is causing the clock to count down. By changing this
instruction, we can stop the clock (infinite time). This
is where a little 68000 assembly knowledge can be helpful.

[01:5DFC] W16 = 0256 [FFC468]
Same as above, except one second less.

[01:5DFC] W16 = 0255 [FFC468]
Same as above, except one second less.

And so on.


After you've done several of these memory traces, you can
quite often just open up the ROM with a hex editor and
go to the ROM address listed and figure out what you need
to know. For example, I can open up my NHL94 ROM with a
hex editor, go to ROM address $015DFC, and instantly see
what instruction I need to change to have infinite time.

But since learning how to read raw 68000 assembly is
something most people don't want to do, here is how you
can make an assembly trace log that will show you everything
that's going on in the CPU, and send it all to a text file
in a "relatively" easy to read format. When you first see
your assembly trace log, it's easy to be overwhelmed by all
the crap in there, but don't let it scare you off. After
you get used to it, it's not really that hard to understand.

An assembly trace log is getting down into the real nuts and
bolts of how a Genesis game works. If you can learn how to
"read" it, you can find all kinds of very useful ROM
addresses (and Game Genie codes).


Okay, here's how to make an assembly trace log. Open up
your NHL94 ROM using Gens Tracer. Get to the first option
screen (the one where you can change Play Mode, Per Length,
etc). Press the "/" key on your keyboard. This starts the
assembly trace log. Now press your "Start" button 3 times
so that you're on the ice and ready to start playing. Wait
for the clock to count down a few seconds and then press the
"/" key again. This stops the assembly trace log. Exit
Gens Tracer. Your newly created assembly trace log has been
sent to a file called "Trace.log"

Keep in mind that the Genesis CPU is operating at about 4Mhz,
so the Trace.log files can be very big.

Remember that everytime you make a new memory trace file, or
a new assembly trace log, the old one will be overwritten.
So if you want to keep any, make sure you rename it.


Now lets open up our new Trace.log file and take a look at
it. I recommend using something like MS Word to open it
with.

We'll start off by figuring out how to make the game have
infinite time. When you have the file opened, use the "Find"
option and type in 01:5DFA. Here's how I came up with that
number... Look at the memory trace we made:

[01:730A] W32 = 00000000 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[01:5DFC] W16 = 0257 [FFC468]
[01:5DFC] W16 = 0256 [FFC468]
[01:5DFC] W16 = 0255 [FFC468]
[01:5DFC] W16 = 0254 [FFC468]

TRACE STOPPED

See where it shows the time starting to count down...

[01:5DFC] W16 = 0257 [FFC468]
[01:5DFC] W16 = 0256 [FFC468]
[01:5DFC] W16 = 0255 [FFC468]
[01:5DFC] W16 = 0254 [FFC468]

0257 seconds
0256 seconds
0255 seconds
0254 seconds

The ROM address shown for each time a second is subtracted
is always the same: 01:5DFC, so we know that the instruction
we're looking for is near by that ROM address. The way that
this memory trace works, you usually need to subtract
2 from the ROM address listed. So to get the ROM address
we need to look for in our Trace.log file, we just need to
subtract 2 from 01:5DFC = 01:5DFA. That's how I came up
with the number to put in the "Find" box.

Alright, back to the Trace.log file... type in the ROM
address we're looking for (01:5DFA) into the "Find" box and
click on "Find Next". Your first match should look like
this:

01:5DFA 53 78 SUBQ.W #1,($C468) .... A0=FFFFBDEC A1=FFFFCA32
A2=FFFFC6CE A3=FFFFB74A A4=FFFFB892 A5=FFFFB8B4 A6=FFFFC060 A7=FFFFFF62
D0=FFFF0100 D1=00000122 D2=00000000 D3=00000183 D4=00000006 D5=0000000C
D6=0000000A D7=00000001 XNZvC

This tells us exactly what we need to know to give us
infinite time. SUBQ.W #1,($C468) means that it is
subtracting 1 from RAM address $C468. If you remember,
FFC468 is our RAM address for time. All we have to do
to get the clock to stop counting down (inf time), is
figure out how to kill that SUBQ.W instruction. We can
easily do this by changing the 5378 opcode shown above
to a branch opcode (6002) instead. This will make the
game jump right over the subtraction part. We can test
this out by making a quick Game Genie code...

Just use a Game Genie conversion program (you can get one
from my web site):

015DFA:6002 = AKRT-CA94

015DFA is the ROM address, and 6002 is the replacement
opcode.

Because it is beyond the scope of this guide, I'm not
going to go into how I came up with 6002 for the opcode
to kill the subtraction. This is where some 68000 assembly
knowledge is helpful. Here's a quick tip... using a branch
opcode (usually 6002 or 6004) is the most common way to
kill many opcodes (subtraction, addition, etc). 6002 will
"jump" 2 bytes, and 6004 will "jump" 4 bytes. You'll
usually want to jump to the next opcode. NEVER jump to
an operand (this can cause the game to freeze).

Anyways, if you try our new Game Genie code (AKRT-CA94)
with your favorite emulator, or on a real Genesis, you'll
see that you now have infinite time.

A little short cut... Gens emulator will let you enter
Game Genie codes in raw format, so instead of converting
the ROM address and opcode into a Game Genie code, Gens
lets you enter it like this: 015DFA:6002. Saves a little
time.

You can easily hack infinite time into your ROM by going
to ROM address $015DFA and changing the 5378 to 6002. Of
course you'll also need to hack the master code too (or
else you'll get a blank screen).

All right, now I'll show you how to find the ROM addresses
for period lengths so you can adjust how much time you
start each period with to any value you want.

Use the same memory trace and assembly trace log as before.

Our memory trace looked like this:

[01:730A] W32 = 00000000 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[00:7830] W16 = 0258 [FFC468]
[01:5DFC] W16 = 0257 [FFC468]
[01:5DFC] W16 = 0256 [FFC468]
[01:5DFC] W16 = 0255 [FFC468]
[01:5DFC] W16 = 0254 [FFC468]

TRACE STOPPED

The ROM address we're interested in here is 00:7830 because
that's the ROM addresses that loaded the initial value of
0258. And remember that 0258 was a hex number which equals
600 in decimal, which equals 10 minutes (which is how much
time we started the period with).

Just like before, we need to subtract 2 from the ROM address
listed in the memory trace to get the actual ROM address that
we'll be searching for in the trace.log file. So 00:7830 - 2
= 00:782E. If you're not sure how to do hex math, just use
your windows calculator. So 00:782E is the ROM address we'll
search for in our trace.log file.

Open up your trace.log file (with MS Word or ?), open up the
"Find" window and type in our ROM address: 00:782E. Click
"Find Next" and you'll notice that your first match isn't on
the far left side of the page. For this example, we're only
interested in matches on the far left side of the page. So
click "Find Next" again. Your second match should be on the
far left side of the page. This is what we're looking for.

Here's what it should look like:

00:782E 31 C0 MOVE.w D0,($C468) .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFFA
D0=C29D0258 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xNzvC


Here's what the first line means...

00:782E 31 C0 MOVE.w D0,($C468)

00:782E is the ROM address of the instruction (opcode).
31 C0 is the opcode.
MOVE.w D0,($C468) means it is moving the value in register
D0 to RAM address $C468. RAM address $C468 (FFC468) is the
amount of time on the clock.

You may be asking... what the hell is register D0? Pay close
attention here, because this is an important part of being
able to read an assembly trace. In my "snippet" above from
our trace.log file, there are a total of 16 registers shown.
Registers are kinda like storage areas. There are 2 types
of registers... The "A" registers are for Addresses, and the
"D" registers are for Data. There are 8 "A" registers (A0
through A7) and 8 "D" registers (D0 through D7). All 16
registers are always listed for every opcode in our trace.log
files. Get to know them, love them,... be one with the
registers. Okay, I'm getting carried away, but registers
are pretty important. We'll need to read the registers to
find the ROM addresses for the values for the period lengths.

From our trace.log snippet above, here's part of the first
line:

MOVE.w D0,($C468)

We know that it "MOVEs" the value in register D0 to RAM
address $C468. If you look at register D0 (above), this is
what you'll see: D0=C29D0258. See the "0258" in there?
That's where our number of seconds for each period is
coming from. All we have to do is figure out where that
value is coming from, and we'll find our ROM addresses.

Let me explain one more thing before we move on... you may
have noticed that the value in register D0 was C29D0258.
Why does the game only use 0258 instead of the entire value
of C29D0258? The answer is because the "MOVE" instruction
has a "w" after it (MOVE.w), and the w means Word. A "word"
is 2 bytes. Here is the list of the letters used and what
they mean...

B = Byte (1 byte)
W = Word (2 bytes)
L = Long word (4 bytes)


Moving on... we know that register D0 cantains the value
that we're interested in (0258). Here's how we figure out
where that value comes from. This gets a bit complicated,
so go drink a big cup of coffee so you'll be extra alert.

To figure out where the value in register D0 is coming from,
we need to read the assembly trace log backwards. Here is
the part of the trace.log that we'll need to find what we're
looking for...

00:7858 30 30 MOVE.w $00(A0,D0),D0 .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFF6
D0=C29D0002 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xnzvc

00:785C 4E 75 RTS .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFF6
D0=C29D0258 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xnzvc

00:7818 0C 78 CMPI.W #$0003,($C466) .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFFA
D0=C29D0258 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xnzvc

00:781E 6D 00 BLT #$000E [00:782E] .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFFA
D0=C29D0258 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xNzvC

00:782E 31 C0 MOVE.w D0,($C468) .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFFA
D0=C29D0258 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xNzvC


For right now, the only thing we're interested in is
register D0. You'll notice that if you start at the
bottom (00:782E), the value in D0 is C29D0258. Reading
backwards (moving upwards one section), the value in D0
at ROM address 00:781E is still C29D0258. No change in
D0 so move upwards to the next section. D0 is still the
same, so move upwards again. When we finally get to the
very top section (00:7858), you'll see that the value in
register D0 has changed. Here's what that section looks
like:

00:7858 30 30 MOVE.w $00(A0,D0),D0 .... A0=0000785E A1=FFFFBFAA
A2=FFFFCA32 A3=FFFFB84A A4=FFFFB88A A5=FFFFD404 A6=00000000 A7=FFFFFFF6
D0=C29D0002 D1=0000FFFF D2=FFFF0000 D3=00000080 D4=0000022E D5=0000000C
D6=00005311 D7=0000000A xnzvc

The value in D0 has changed to C29D0002. The 0258 part
is gone. So we know that this is the line that loaded
the number of seconds (0258) into register D0. This
line of code will tell us what we need to know. Drum
roll please...

MOVE.w $00(A0,D0),D0

I know it may seem a little cryptic, but here's what
it means: see where it says (A0,D0)... that means you
take the 2 byte value in D0 (0002) and add it to the
ROM address in register A0 (remember, the A registers
are for Addresses). A0=0000785E so 0000785E + 0002 =
00007860. If you go to ROM address 00007860 with your
hex editor, this is the value you'll see: 0258. BINGO!!
We found it! This is the value that the game uses for
10 minute periods. You can change that value to any
number you want with a Game Genie code, or by hacking
the ROM. A value of 0001 would give you 1 second periods,
001E would give you 30 second periods, etc. Just remember
it uses hex values. And remember it will only work when
you select 10 minute periods (the default time).

Here's a couple Game Genie codes:

007860:01A4 = YV6A-ACDA
7 minute periods. Only works when you leave the period
length at 10 minutes.

007860:003C = HV6A-AADA
1 minute periods. Only works when you leave the period
length at 10 minutes.


Here's some "extra" info.

If you look at the ROM address (with your hex editor)
where we found our value for the 10 minute periods, here
is what you'll see around it:

012C 0258 04B0 001E

These are all the values for the other period lengths.

012C = 5 minute periods.

0258 = 10 minute periods (this is the one we found).

04B0 = 20 minute periods.

001E = 30 second periods (this is for the controller cheat).


You can change those values to anything you want, and
if you selected that particular period length in the
option screen, your new "hacked" time would kick in.


Well, that concludes our ROM hacking 101 class. As I
said before, after you've done a few, reading an
assembly trace log gets easier. Just remember that
you don't need to know what everything in the trace.log
means, just the part you're interested in. To be
honest with you, there is still a lot of stuff in there
that I don't completely understand. Get to know the
basics and you'll find lots of useful stuff.


Tony H.