Copy Link
Add to Bookmark
Report

Making Game Genie's SNES codes from binary files

Nintendo's profile picture
Published in 
SNES
 · 4 years ago

Before reading this section, start with the NES tutorial. This tutorial will only cover changes and additions involved in making codes for SNES games. Most of the information is very similar to that for the NES, and the basic program instructions are identical.

SNES code making--preparing your file


As with NES games, it pays to trim as much unneeded stuff from your game as possible before disassembling. You will need a hex editor and a 65c816 disassembler, and you might get some use out of a graphic editor. All of these are available in the file section.

We'll use our sample game, FOOBAR2.SMC. Your game will probably have an .SMC extension, although .SFC also pops up often. In one case, I've even seen a partial split section of a game with a .1 extension. Anyway, start by making a copy of the game. We'll use the name FOOBAR2.BIN, but the name doesn't matter. This will be your work copy. All changes that you make will be made to this file.

First, open your hex editor and look inside your work copy. Are there a lot of zeros at the top? In most games, there should be a line with a few numbers in the beginning, then every other line from $10 to $200 should be empty. If this is true, delete everything from $0 to $200 from your work copy. I can think of a game which does not have this header, however, so don't delete the top of the file if it isn't empty.

Now, you might want to look at the game in the graphic editor as you did with your NES game. It certainly can't hurt, but don't hold your breath. The SNES is capable of decompressing squished graphic data in the cartridge as you play the game, so most of the game's graphics--if not all--won't be visible to the naked eye. Our FOOBAR2.BIN has a few sprites towards the bottom, but there aren't enough to account for the whole game. If everything from a certain point in the file all the way down is full of graphics (or if everything from the beginning down to a certain point is), go ahead and delete that section, following the instructions in the NES tutorial. If the graphics are interspersed with non-graphic stuff, you should probably leave it alone.

How big is your work copy? If it's still around the 2 MB mark, you will have to split off one small piece at a time to work with. A 2 MB game usually becomes a 30 MB text file when disassembled. Yikes! I usually find that the best and most important stuff in a game lives within the first 150-200K. (This isn't so unreasonable, considering that the actual program of most NES games is less than 64K long) Since your original game is still untouched, you can always repeat these steps and break off a bigger chunk if you discover that this isn't enough. So, consider going into your hex editor and removing everything after $28000 or so from your work copy. Even then, the resulting translation will probably be the size of the original game.

Now that we've put our FOOBAR2.BIN on the Qwik-Lose Diet, it's time to disassemble it. This part can be tricky to the uninitiated. The program in the file section, Tracer, has about a billion options. Worse, they're case sensitive! Which to use? The only option you really need is REP/SEP tracing, the '-f' option. You can try adding the HiROM option if you have a HiROM game (let your emulator tell you), but it doesn't seem to work with the '-f' option, which you must use. It's only an asthetic change that makes it easier to get the CPU address; we'll see how to get it without the program's help. Don't mess with the odd things like 16-bit registers. Oh, and remember that the output of the program goes to the screen and has to be piped into a file. Here's our command line:

 
D:\SNES> tracer -f foobar2.bin > foobar2.asm


The last name--FOOBAR2.ASM here--is up to you. That's just the name of the text file that will hold the results. You could also use the built-in option to save to a file, but the name will always be OUTPUT.DIS. Besides, if you're willing to learn basic SNES assembly, you can't be afraid of DOS, can you?

Open up the results and see what they look like. If you read through the NES section, the stuff in your file should look at least somewhat familiar.

SNES addresses


Here's a sample of the first line in the disassembled file.

 
00/8000: 78 sei


It looks the same as the NES files, except that the address is funny. Not only does it contain strange punctuation, the file doesn't start at $0. If you hated figuring out the CPU ROM address from the file address before, you're going to love this. The address at the beginning of each disassembled line is the CPU address! Well, if it's a LoROM game, anyway. Let's go over the CPU ROM space inside a SNES.

A game can come in one of two flavors: LoROM and HiROM. The most common type is the LoROM game. These games should sound familiar to NES gamers: they load 32K of the game into each of a number of "pages"--64K storage areas--the first usually being called number $80. The 32K sections fill the upper half of each page, from xx/8000 to xx/FFFF. That's where the weird punctuation comes from: the disassembler is trying to remind you that the first two digits are separate from the other four. (No SNES code converter I've ever seen does this, so drop the slash before you punch in your hex code!) The pages can also begin at number $00, but most games start at $80. Here's what the ROM usually area looks like:

 
80 8000
80 A000
80 C000
80 E000
80 FFFF -|
81 8000 -| 3rd digit always >= 8
81 A000
:
:
BF E000
BF FFFF


LoROM games can fill at most 32K of each of 40 pages, for a total of 1.25 MB (or, in consolespeak, 10 Mbits). Hmm, that figure sounds a bit low... Eh, say 1.5 MB to be safe.

The other type of game is the HiROM game. These load 64K of themselves into each page, from xx/0000 to xx/FFFF. Most begin with page number $C0, but they technically can start at $80 to maximize their storage potential. They could also technically start at $00 or $40, but I doubt that ever happens. ($80+ is best for speed reasons) Here's a typical HiROM game:

 
C0 0000
C0 2000
C0 4000
C0 6000
C0 8000
C0 A000
C0 C000
C0 E000
C0 FFFF
C1 0000
C1 2000
:
:
FF E000
FF FFFF


HiROM games technically can fill 64K of each of 80 pages, for a total of a whopping 5 MB (40 Mbit... but I know they said 48 Mbit was the highest?). Since most games start at $C0 instead of $80, however, the realistic maximum is more like 2.5 or 3 MB.

The addresses listed in a disassembled file are LoROM CPU addresses. The first page is always number $00 for some reason ($80 would have been more accurate in most cases). This is wonderful, unless you have a HiROM game. The easiest way to tell if you do is to find a copy of SNES9x at Zophar's Domain and let it tell you when you start the game. ZSNES, available from the same location, will also tell you if you start the game from the command line (i.e. zsnes foobar2.smc). The other way is to open the original game in your hex editor and go hunting. The name of the game should appear in regular text somewhere around either $7FFF or $81FF in a LoROM game, and either $FFFF or $101FF in a HiROM game.

What if you have a HiROM game, and your file is giving you LoROM addresses? The easy fix is to use the code converter in the file section. Enter your hex address (minus the slash!) into the appropriate box, followed by any two-digit number into the box next to it, then press the little button that says "Show 64K." The associated HiROM address appears to the side, along with the Genie format of your temporary code. This only works on games that begin at page $C0, but most do.

The manual fix involves math. Take the first two digits of your address, divide by two, and add the result to $C0. If you have one left over, the last four digits are fine. If it divided evenly, subtract $8000 from the last four digits. Shove the new first two digits and the new last four digits together to get the answer.

If you have the exceedingly rare HiROM game that begins at $80 instead of $C0, you have to do some strange math. The game fills addresses $80/80000 through $BF/FFFF in the same way as a LoROM game. Thus, the first 2 MB of the file (file addresses $00/8000 through $3F/FFFF) are treated the same way as are LoROM games. After this, the rest is treated the same way as are HiROM games. Thus, the rest of the file (file addresses $40/8000 on) becomes CPU addresses $C0/0000 on. To calculate the file address of the game after this point, convert the CPU address to a file address as usual and subtract $400000 instead of $800000.

Oh, and one final note. When I talk about "file addresses," I'm assuming that you are looking at the disassembled file, not the original game binary. If you find something interesting in a hex editor, you have to convert the address in the hex editor into what would have been the address listed in the assembly dump. You can do this the same way you convert HiROM codes into LoROM addresses, which is described at the bottom of the tutorial ("Locating existing codes"). Just add $C00000 to the hex editor address to get the HiROM address, then convert away. This cheap trick works because HiROM addresses fill all of the available space and run the same way as hex addresses.

SNES RAM addresses


On the NES, everything from $0 to $800 was RAM, and everything else wasn't. You could tell at a glance if an address was in RAM or not. Here it's a bit trickier. As far as the CPU addresses go, everything from $7E/0000 to $7F/FFFF is RAM. You usually won't see the full-blown three-byte addresses in the game, though. Is $8092 in RAM? Maybe, maybe not. They might mean $7E/8092, or they might mean $84/8092. They might mean something else entirely.

How can you tell, then? Luckily, there is usually a way. For the most part, LDA (and its siblings, LDX and LDY) takes its addresses from RAM. Unless the game gives the entire three-byte address and that address doesn't begin with 7, you can probably assume that it is in RAM. The store operations obviously always operate on RAM (you can't change ROM), as do the math operations.

Computer-moving instructions such as JMP and BMI always take their addresses from ROM. These instructions refer to another part of the program, which is only found in ROM.

Generally, you should be able to figure out from context clues which addresses are in RAM. So, now that you've seen the new SNES addresses, it's time to look at some new program instructions.

SNES-only instructions


Every single program instruction on the NES is also on the SNES. The addressing modes are the same, and even their numbers are the same. You can refer to them through one of the tech docs in the file section (the 65c816 instruction table is my favorite) or the code converter in the same place. The same registers you know and love--A, X, and Y--are still the most important here and all work the same way.

In addition to the old 6502 commands, the SNES also has a number of new ones. Most of these aren't important as far as code making is concerned. Here's the most noteworthy ones:

 
1A INC INC implied
3A DEC DEC implied


These are the same as the NES increment and decrement, but they work on the A register instead of on RAM. Of course, your old favorites are here, too.

 
80 BRA L BRA relative


BRA is an unconditional branch--that is, it moves the computer up or down a few lines in the program, no matter what. (Remember, all of the NES branches only worked half of the time)

 
82 BRL Lq?? BRL relative long


BRL is like BRA, but it moves the computer up or down many, many lines.

 
22 JSL M JSL absolute long


JSL is like JSR on a rocket engine. JSL can jump temporarily to a location anywhere in the entire cartridge! (Like the NES version, which could only go somewhere in the current ROM area, the regular JSR can only go somewhere in the same page)

 
6B RTL RTL implied


RTL is the big brother of RTS. This makes the computer jump back to the location of the last JSL it performed and continue with the next line.

 
DC JML (Q) JML absolute indirect


JML makes the computer go anywhere in the entire cartridge, with no intention of coming back. Apparently, the three-byte location to go to has to be stored inside of the two-byte address Q, and the CPU looks it up from there.

 
00 BRK #n BRK immediate


This BRK is the same as the NES version, but it is now followed by a number. (This replaces the old BRK)

 
64 STZ Z STZ direct
74 STZ Z,X STZ direct indexed w/ X
9C STZ Q STZ absolute
9E STZ Q,X STZ absolute indexed w/ X


STZ, or "store zero," is rather similar to commands such as STA. The difference is that the number 0 is placed into the RAM address following the command, instead of the contents of a register. This is good for the programmer and bad for you. We'll see why later. (Amusingly, a bunch of geeks wanted this one renamed because they thought STZ looks too much like "store the contents of the Z register")

 
C2 REP #n REP immediate
E2 SEP #n SEP immediate


REP ("reset P" or "reset processor status") and SEP ("set P" or "set processor status") are used for boring, complicated housekeeping tasks. Why do you care? REP and SEP are what make the registers bigger. By default, the three main registers can hold only one byte, just like the NES. However, these instructions can make them hold two bytes instead. Consider this piece of a program:

 
00/8000: E2 30 sep #$30
00/8002: A9 12 lda #$12
00/8004: C2 30 rep #$30
00/8006: A9 34 12 lda #$1234


Both lines $00/8002 and $00/8006 begin with the exact same instruction, $A9 or LDA #n. Yet, one loads a one-byte number and the other loads a two-byte number. Why? The registers are always filled to capacity, and that REP just made them bigger.

A useless factoid to remember regarding the size of each register is that X and Y must be the same size. A can be different, though. Anyway, you will find that all three registers are one byte in length most of the time. The game will expand them just long enough to do some big math, then immediately shrink them again. It's like the above example, but the REP comes before the SEP and everything between them is twice as large.

 
42 WDM #n WDM immediate


On the SNES, WDM is about as much good as NOP. The difference is that it brings the next byte down with it. (Fun fact: WDM comes from the engineer's initials) When you see this in a game, rest assured that you are looking not at program but at data.

The terrible STZ


Judicious use of the STZ instruction can save a lot of space and processing time. This is bad. Huh? The Game Genie cannot insert new bytes; it can only replace existing ones. Anything that reduces the number of bytes in the program also reduces your options. For example, here is a piece of an NES program that sets your initial cash supply to zero:

 
LDA #$00
STA $1234


If you want to start with some money, you just change the amount loaded into A. That amount is then placed in your wallet. Now, look at the same thing in a SNES game:

 
STZ $1234


What on Earth are you supposed to do with that? You can't change the number $0 now because it's hard-wired into the CPU. You would have to change something else into a LDA #n, then change the STZ into a STA. If you're lucky, there may be an expendable LDA already available. Even then, though, the value in A is meant to be used for something else, and the game may not like you changing it. For example:

 
LDA $3C
JSR $6014
STZ $1013
STZ $1014


A is loaded with something, then the computer goes away for a while. When it comes back, the two other addresses are emptied. Unless you scroll to the place given in the JSR, you can't tell what A is going to be used for. Go ahead and try changing the existing LDA first, but don't be surprised if the game does something strange.

If the LDA doesn't work and it's the second STZ you're interested in, you could rewrite the entire line above it. Depending on what you need in A, though, that could take anywhere from one to three bytes. You still need to spend a byte changing the STZ to a STA; by the time you're done, there may only be enough room left for one other code. (Remember, each Genie code replaces a single byte, and each Genie only holds five bytes' worth of codes) There's also the possibility that the game will still glitch because you're overwriting the STZ $1013 line, leaving $1013 in an unknown state.

If the LDA doesn't work and you need to change the first STZ, you'll have to rewrite both STZ lines. You'll have to make the first line into your LDA, then change the second line to STA $1013. Depending on what you need loaded into A, this could take up your entire Game Genie. Also, $1014 won't be emptied anymore, leaving the possibility of a glitch.

We'll use this scenario as an example later. This is probably a good time to review Game Genie codes and game editing.

SNES codes


Unlike NES codes, SNES codes do not include check values. Remember, the NES needed a check value to tell if it was looking at the right part of the game or not. The SNES can remember the entire game at once, on the other hand, and your codes will point to the exact spot in the game that they affect. This is even better for you, as there's no chance that two parts of the game at the same relative position will contain the same thing. You aren't using relative positions anymore.

The hex format of a code is simple: the address comes first, followed by the data. A colon is shoved between them to separate the two parts. If your address is $80/81C7 and your data is $3C, the hex code is 8081C7:3C. Remember, the slash isn't really part of the address, so you'll need to get rid of it.

The real trick is knowing where the game starts. Assuming you have a LoROM game, you should first add $800000 to the address listed in the file. ($00/8000 becomes $80/8000, etc.) This is necessary for the vast majority of LoROM games. A few here and there don't like it, though. If the code doesn't work and you're positive that it ought to, try using the file address directly.

Should you have a HiROM game, you will have to convert the file address as explained above. If the resulting code doesn't work, and you are positive both that it should and that you converted it right, try subtracting $800000 from the address. ($C0/0000 becomes $40/0000, etc.) If that doesn't work either, subtract $400000 from the original address. ($C0/0000 becomes $80/0000) As a last resort, try subtracting $C00000 from the original address. ($C0/0000 becomes $00/0000) Obviously, you have to be pretty confident that the code is perfect to go to this much trouble. Still, if you can't get anything to work, it may be worth the time to figure out where the game starts.

SNES hex codes are a pain in the kisser to convert to Genie format by hand. You should find a code converting program to do it for you. There's one in the file section, for example.

Evil STZ revisited


It's time to practice turning program changes into hex codes. Why not practice on a practical example? Let's look at our hum-dinger again. This time, we're sticking SEP #$30 in front. For now, we're going to keep things simple and assume that A holds a single byte. We'll mix it up later and look at a case where A holds two bytes.

 
C1/2011: E2 30 sep #$30
C1/2013: A5 3C lda $3C
C1/2015: 20 14 60 jsr $6014
C1/2018: 9C 13 10 stz $1013
C1/201B: 9C 14 10 stz $1014



(Quick quiz: What type of game is this? It has to be HiROM, because the third digit of a LoROM address is always at least 8. Your file won't look like this because the disassembler's HiROM mode doesn't work.)

Okay, let's try each of the three scenarios listed above. What we want to do is to store the number $40 address $1013. First we'll see if we can borrow the LDA that's already up there. It's the wrong type of LDA, though, and it loads the wrong number. The LDA we want takes a number directly. That would be LDA #n, which is number $A9. So, we'll start by changing the number at address $C1/2013 into $A9. Next, we need to change the actual number being loaded. The number is at address $C1/2014, and we want to replace it with $40. Finally, we need to change the STZ $1013 into STA $1013. The STA that takes a two-byte address is STA Q, or number $8D. So, we will be changing the instruction at $C1/2018 into $8D. This process gives us three hex codes: C12013:A9 , C12014:40 , and C12018:8D .

 
C1/2011: E2 30 sep #$30
C1/2013: A9 40 lda #$40
C1/2015: 20 14 60 jsr $6014
C1/2018: 8D 13 10 sta $1013
C1/201B: 9C 14 10 stz $1014


What if we wanted to put the $40 into address $1014, and we couldn't get away with changing the existing LDA? We'd have to change the STZ $1013 into a LDA instead. Problem is, the LDA #$40 we were using takes two bytes, and STZ $1013 is made up of three. You might tweak the SEP #$30 to make the LDA longer, but that would screw up everything else! (In general, you shouldn't mess with REP and SEP) We'll do it the brute force way: pad with NOPs.

First, we want to change the first STZ into a LDA #n. We've already seen that this is number $A9. We'll be putting that $A9 into $C1/2018, the location of the STZ. Next, we'll put our number $40 to be loaded into the next byte, $C1/2019. If we stopped here, the $10 at $C1/201A would be left over. $10 represents BPL, and we don't want a BPL. We'll kill the $10 by putting NOP over it. NOP doesn't do anything, so it won't hurt to add one. The number of NOP is $EA, and we want it at $C1/201A. The last step is to change the STZ $1014 into STA $1014. We put the STA in by replacing $C1/201B with its number, $8D. This process leaves us with four hex codes: C12018:A9 , C12019:40 , C1201A:EA , and C1201B:8D .

 
C1/2011: E2 30 sep #$30
C1/2013: A5 3C lda $3C
C1/2015: 20 14 60 jsr $6014
C1/2018: A9 40 lda #$40
C1/201A: EA nop
C1/201B: 8D 14 10 sta $1014


Notice the way the line breaks changed. The three-byte line at $C1/2018 was replaced by a two-byte line, causing the last byte to move down.

Now, what if we wanted the $40 in address $1013 after all, but we couldn't use the LDA that was already there? We have to do the same thing, but we also have to change our new STA $1014 into STA $1013. The first four codes are the same. To them, we will add C1201C:13.

 
C1/2011: E2 30 sep #$30
C1/2013: A5 3C lda $3C
C1/2015: 20 14 60 jsr $6014
C1/2018: A9 40 lda #$40
C1/201A: EA nop
C1/201B: 8D 13 10 sta $1013


See the problem? That last scenario took five codes. You only get five codes on a real SNES. Anyway, you should see how SNES codes are constructed. The process is the same as for the NES, but the original value being replaced isn't part of the code.

Evil REP/SEP


The reason the above example contains a SEP #$30 line is to show that the A register only holds one byte. You cannot always assume this. The best way to tell how big the registers are is to follow context clues. Using the '-f' option (you did, didn't you?) allows the disassembler to figure it out for you. It doesn't spell it out, though. Look at the following and tell me which A's are 8-bit and which are 16:

 
LDA #$04
REP #$30
LDA #$0412
SEP #$30
LDA $1234
LDA #$15
REP #$20
LDA $31
SEP #$20
LDA #$10


Yeesh! What a horrible mess. The first A is clearly 8-bit. Why? Remember that LDA #n always bites off as much as it can chew. It only took one byte, so we know that A only holds one byte. The second is clearly 16-bit for the same reason.

How about the third? $1234 is an address, not a number. Anything could be inside of there. Yes, but remember that only REP and SEP can resize A. Every A in the same spot is the same size. It doesn't change until you hit another REP or SEP. The A right underneath it is only one byte long. There weren't any opportunities for it to change after this one, so this A must also be one byte long.

What about the fifth? Unless you happen to know that any REP #n containing the $20 bit makes A 16 bits long (don't memorize this), you can't tell from the LDA alone. However, you can guess. The two As flanking it are both 8-bit. If this one were also, why did they bother with the REP at all? They went out of their way to change it, so we can reasonably assume that the fifth A is 16-bit. Granted, this isn't a surefire assumption, as REP does do things other than simply resizing registers. Still, it's a decent educated guess.

Now, suppose our STZ example looked like this instead:

 
C1/2011: C2 30 rep #$30
C1/2013: A5 3C lda $3C
C1/2015: 20 14 60 jsr $6014
C1/2018: 9C 13 10 stz $1013
C1/201B: 9C 14 10 stz $1014


The difference is that it begins with REP now. REP makes the registers 16 bits long, and SEP makes them 8 bits long. That means that A here now holds two bytes. This eliminates any hope of using the existing LDA if you still want the number $40 specifically. Why? To load A with a specific number, you use LDA #n. But, under 16-bit conditions, LDA #n must be followed by two bytes. There's only one byte between the old LDA and that JSR, so you can't squeeze it in. There is hope, though. Remember how we actually had to pad the fourth line with NOP because there was too much room? We need that extra room now.

Start the same way: replace the STZ at $C1/2018 with LDA #n ($A9). Now we have to replace the rest of the line with our number $40. The two-byte version of $40 is $0040. But, don't forget that numbers more than one byte long are stored somewhat backwards! Remember, the last pair of digits comes first, followed by the pair to the left of it, and so on. To the computer, our number looks like "40 00." That's the order it has to go in. Replace $C1/2019 with the $40, then replace $C1/201A with the $00. Finally, we can replace the second STZ with a STA by changing $C1/201B to $8D. Our four hex codes are C12018:A9, C12019:40, C1201A:00, and C1201B:8D.

 
C1/2011: C2 30 rep #$30
C1/2013: A5 3C lda $3C
C1/2015: 20 14 60 jsr $6014
C1/2018: A9 40 00 lda #$0040
C1/201B: 8D 14 10 sta $1014


Evil TCD


What, there's more about the SNES to hate? This was supposed to be easier than NES, right? Actually, I've never seen this in any game. It's only included as a warning. On the NES, a one-byte address was a one-byte address. $3C was the same as $003C, $F1 was the same as $00F1, $12 was the same as $0012, etc. The same is true of the SNES... mostly. Both the 6502 and the 65c816 have something called a "direct page." This is a spot in RAM used as the starting offset for one-byte addresses. Huh? In other words, the direct page address is added to every one-byte address. On the NES, the direct page address is always $0000.

On the SNES, that can change. A dirty little something called the direct page register contains this base address, and it usually contains $0000. However, the TCD command (not important enough to list here) allows devious programmers to copy the contents of the A register into the direct page register. What does that mean? It means that one-byte addresses can move. Consider the following:

 
$0010 = #$12
$4010 = #$8D

LDX $10
REP #$20
LDA #$4000
TCD
SEP #$20
LDY $10


What do X and Y hold? If you thought, "Well, X and Y are both loaded from address $10, so they must be the same," you're wrong. Yes, X was loaded from address $10, which contains the number $12. So, X contains $12. Shouldn't Y also contain $12? Here's what went wrong: A was loaded with the number $4000, and that number was transfered to the direct page register. Remember, the contents of the DPR are added to every one-byte address. When the LDY asks for address $10, the $4000 in the DPR is added to the $10 to yield an address of $4010. $4010 contains the number $8D, so Y now contains $8D.

Evil, isn't it? Just when you thought you knew something... But don't worry; I've never actually seen this happen.

Creative AND use


Okay, way back in the NES section I promised to explain bit flags. To understand them, you have to be familiar with binary numbers. Each bit in a number has a hex value (sorry about the indentation, FrontPage is being stupid as always):

 
0 0 0 0 0 0 0 0
$80 $40 $20 $10 $8 $4 $2 $1


You figure out the hex equivalent of a binary number by adding up the hex value of every 1 in the number:

 
0 1 0 1 1 0 0 1
$80 $40 $20 $10 $8 $4 $2 $1

$40 + $10 + $8 + $1 = $59


Not too hard, right? Now, consider the above binary number. Is the bit with the value $40 in the number? A bit is "in" a number if it is equal to 1. Sure, the $40 bit is equal to 1, so we say that the number contains the $40 bit. Is the $2 bit in the number? No, that bit is equal to 0.

Here's where AND comes in. The binary AND operation, according to a math book, "returns true if both arguments are true." What the heck? This isn't math class, so we're going to make this clearer. Basically, AND looks to see if one or more bits are "in" a number. Take the above example. $59 AND $40 means "check to see if the $40 bit is equal to 1 in the number $59." This is true. $59 AND $2 means "check to see if the $2 bit is equal to 1 in the number $59." This is false.

Note that I said "one or more" bits. You can use AND to see if more than one bit is in a number by adding up the hex value of each. Say you want to see if both the $40 and the $10 bits are in the number $59. First, add up the values of all the bits to be tested. We want $40 and $10, which add up to $50. Now, AND your number with that result. We would say "$59 AND $50" to look inside $59 for both the $40 and $10 bits. When all of the bits being tested are in the number, you get a "true" or nonzero result. If even one of them is missing, you get "false" or zero.

Quiz! We'll stick to $59 since it's already broken down above. Which of the following are true?

 
$59 AND $1
$59 AND $80
$59 AND $9
$59 AND $C0
$59 AND $59


The first is true, because the $1 bit is in the number. The second is false because the $80 bit is not in the number. The third is true. Where did the $9 come from? Given the above hex values, only $1 and $8 can be added together to get $9. Both the $1 and $8 bits are in the number, so we say that $9 is in the number. Similarly, the fourth is false. $C0 can only come from adding $80 and $40 together. The $40 bit is in the number, but the $80 bit is not. Both have to be in the number for this to be true. Thus, we say that $C0 is not in the number. How about the last? The bits in $59 are the same as the bits in, er, $59, right? All of the bits in $59 are in $59... Seriously, a number AND itself is always true.

Now, how does this math lesson relate to games? Many games contain a large number of true/false, on/off, yes/no, or other such "binary" (two option) quantities. One byte holds eight bits, and each bit is a yes/no type of value. That means that a single byte can effectively hold eight of these game values crammed together. The hex value of each bit is also assigned to a game value:

 
0 $80 Red key
0 $40 Blue key
0 $20 Yellow key
0 $10 Flamethrower
0 $8 Lightning gun
0 $4 Beam saber
0 $2 Jump boots
0 $1 Body armor


Each of these inventory items is represented by a simple "have/don't have" value. If an item's bit is in the inventory byte, the item is in the inventory. If an item's bit is not in the inventory byte, that item is not in the inventory. In the above example, you have nothing. How about this?

 
0 $80 Red key
1 $40 Blue key
0 $20 Yellow key
0 $10 Flamethrower
1 $8 Lightning gun
1 $4 Beam saber
0 $2 Jump boots
1 $1 Body armor


Here, the $40, $8, $4, and $1 bits are in the number. According to the chart, that means that you have the blue key, the lightning gun, the beam saber, and the body armor. Simple, right? So, how does the game know if you have the blue key or not? The CPU only works with numbers. It doesn't even know what a key is, much less a blue one. But that's okay, because the above chart shows that the blue key is associated with the $40 bit. The CPU can handle $40.

To see if a bit is in a number, you use AND. So, to see if the $40 bit is in your inventory, you AND it with $40. What is the inventory number? Add up the bits that are in it: $40 + $8 + $4 + $1 = $4D. So, the entire inventory above can be summarized by the number $4D. This is where you use AND. $4D AND $40 is true, because item $40 is in inventory $4D. How about the red key? That's item $80. $4D AND $80 is false, because the $80 bit is not in the number right now.

Time for another quiz. Given the following combination of items, which statements are true?

 
0 $80 Red key
1 $40 Blue key
1 $20 Yellow key
0 $10 Flamethrower
0 $8 Lightning gun
1 $4 Beam saber
1 $2 Jump boots
0 $1 Body armor


Inventory AND $1
Inventory AND $60
You have the lightning gun
Inventory AND $4
You do not have the flamethrower

How about the first? Is the $1 bit equal to 1 in the above figure? No, so this is false. What about the second? Given the listed hex values, $60 can only be a combination of $40 and $20. Both the $40 and $20 bits are equal to 1, so this is true. Hmm, the third is in English. What does it mean to have the lightning gun? According to the chart, the lightning gun is represented by the $8 bit. The $8 bit is not equal to 1, so it is not in the inventory. That means that you do not have the lightning gun. The fourth is like the first two. Is the $4 bit equal to 1? Yes, so this is true. We have to translate the last one. The flamethrower is represented by bit $10. Bit $10 is equal to 0, so it is not in the inventory. That means that you do not have the flamethrower, making the statement true.

This is all great, but the game won't give you a list of items and their associated bits. All you'll see is this:

 
LDA $1234
AND #$40


If you know that the address $1234 contains your inventory, then you can guess that this checks your inventory for the item represented by the number $40. You can then fool with the game in this area to make it think you always have that item. One possibility when you see this is to change AND to OR. Without delving into more math, we can say that OR adds things in the same way that AND looks for things. OR #$40 would give you item $40 just long enough to convince the game that you have it. It might also be possible to change a nearby conditional test from "do this if I have the item" (BPL, BNE) to "always do this" (BRA).

The SNES code finder


The process of finding new codes for a game is about the same as it is on the NES. In fact, you can still do it the same way. (Here's where we find out which of you read the NES tutorial first as I told you to, and which of you didn't!) In addition, though, you now have an insanely powerful tool: an internal memory search. Well, maybe. If the game can run in a SNES emulator, you have an insanely powerful tool. If not, you have to do it the old-fashioned way.

Anyway, most programs support internal memory searching or Pro Action Replay code finding. This can save you hours of guessing which of 1,500 "LDA #$03"s starts the game with three lives. It also allows you to find abstract quantities such as energy bars without needing an existing code to calculate their RAM addresses. Refer to your software's documentation for an explanation of how to use the memory search.

When you get a code through the search feature, it always begins with either $7E or $7F. This is the mark of a RAM address. Remember our notation for CPU addresses? Say you get $7E0C77 from the search feature. Separating the page and offset, we would write this as $7E / 0C77. What's a page, again? That's the number of the 64K division inside the CPU holding the stuff we want. The offset is the address within that division. In this case, we are looking inside page number $7E, at address $0C77. Pages $7E and $7F are devoted to RAM, and all of the codes you get from the search will be here. Actually, you will probably only get codes that begin with $7E.

When you look at your disassembled game, though, you almost never see this. Here's what you might see in the game:

 
LDA #$1C
STA $0C77


Hmm, is that $0C77 the one we want? How can we be sure that this isn't $C0/0C77, $D2/0C77, or anything else? Look at the way it's being used. STA changes the contents of the given address. Only RAM is allowed to change during the game. Only $7E/0C77 and $7F/0C77 would be in RAM. Thus, we're down to a 50% chance of it being right. So, is it $7E or $7F? When in doubt, assume it is $7E. I actually have yet to see one that isn't. Thus, we'll assume that STA $0C77 really means STA $7E0C77, and that this is what we want.

What if it isn't so obvious? The one above had to be in RAM because it is changed. What about this:

 
LDA $0C77
STA $3042


Is this our $7E/0C77? I'm still tempted to say that it is. If you just aren't sure, look for another part of the game that changes the address. If it's used in the game, it almost has to be initialized or changed somewhere. Once you see it change, you know it's in RAM.

Okay, so what have we learned? We now know that the search feature gives us full RAM addresses, and that the game uses them without the first two digits. $7E/xxxx in the search looks like $xxxx in the game. So? Remember, if you know the RAM address of a game quantity, you can search for parts of the game that change it. Drop the first two digits of the search results, and you have that address.

As an example, we'll load up the game and run a search for the number of lives. We start with three lives, so search for three. Next, jump down a hole and search for two. Eventually, the computer returns $7E2024 as the location of our lives. Is this right? In the cheat menu of the program, enter the code "7E202403." This is the Pro Action Replay format of the hex code $7E2024:03. If the address is right, we should have infinite lives. Jump down the nearest hole. Still have three lives? Good. Start by dropping the first two digits of the address to get $2024. Next, open up the disassembled copy of the game and search for references to the shortened address. In particular, there should be a LDA/STA pair that puts three lives into the address at the start of the game, and either a DEC or a LDA/SBC/STA set that decreases your lives when you die. Here's what we find:

 
80/9123: A9 03 lda #$03
80/9125: 8D 24 20 sta $2024

80/C072: CE 24 20 dec $2024
80/C075: F0 1A beq $80C08F


These are good. It's pretty clear that the first block gives you three lives at the start of the game, and that the second takes one away when you die and then checks to see if you have any left. Still want infinite lives? Kill that DEC and you should have them. Let's look at that part in more detail.

 
80/C06E: A5 47 lda $47
80/C070: 85 48 sta $48
80/C072: CE 24 20 dec $2024
80/C075: F0 1A beq $80C08F


As long as $47 doesn't contain a zero, A here shouldn't be zero (A is loaded from $47). If you know that A isn't zero, you could replace DEC with STA. That would provide a simple one-code solution. We need to change $80/C072 into $8D (STA Q), which is the hex code 80C072:8D.

 
80/C06E: A5 47 lda $47
80/C070: 85 48 sta $48
80/C072: CE 24 20 sta $2024
80/C075: F0 1A beq $80C08F


What if you're playing merrily along, and suddenly find yourself with no lives for no reason? Maybe $47 wasn't well-behaved after all. If you're willing to mess up the contents of $48, you could load A with the number $47 instead of the address $47. That would add the hex code 80C06E:A9, which changes the LDA Z in the first line to a LDA #n.

 
80/C06E: A9 47 lda #$ $47
80/C070: 85 48 sta $48
80/C072: CE 24 20 sta $2024
80/C075: F0 1A beq $80C08F


Of course, there's three problems with this. One, as stated, address $48 is now being filled with something vastly different than usual. Two, many games tend to balk when you have more than 9 lives, much less 71. Three, it's a terrible shame to use two codes for something that might be done as well in only one. Let's keep looking.

 
80/C06E: A5 47 lda $47
80/C070: 85 48 sta $48
80/C072: CE 24 20 dec $2024
80/C075: F0 1A beq $80C08F
80/C077: A2 03 ldx #$03
80/C079: A0 14 ldy #$14
80/C07B: AD 01 10 lda $1001


Ah-ha! Look way below the DEC. See, there's a LDA down there. That means that we can mess with A all we want, because it's going to be reloaded later. If only we'd seen this sooner! A simple solution, then, is to change the DEC into a LDA. In short, we need the hex code 80C072:AD ($AD = LDA Q).

 
80/C06E: A5 47 lda $47
80/C070: 85 48 sta $48
80/C072: AD 24 20 lda $2024
80/C075: F0 1A beq $80C08F
80/C077: A2 03 ldx #$03
80/C079: A0 14 ldy #$14
80/C07B: AD 01 10 lda $1001


See how much trouble code making can be? You have to consider two or three scenarios at once and try to pick the best one. Don't be surprised if you have to try five different codes before one works.

Anyway, this should give you some idea as to how you can find the addresses of game quantities for use in cheating. Once you have them, the process of turning them into codes is the same as for NES games. You do have a bit more flexibility here, though, thanks to the new program instructions.

Locating existing codes


You can use codes you already have as a starting point for making new codes. This is the same as for NES games: find the code in your file and figure out what the program there does and how the code affects it. Generally, it is much easier to find the file address of the code, as the file addresses almost are the CPU addresses. If you have a LoROM game, your code is either at the location given in the file, or more likely, is $800000 ahead of the file address. If your code begins with a digit 8 or greater, just subtract $800000 to get the file address. So, $80/A904 is located at $00/A904 in the file.

If you have a HiROM game, you have to adjust the code first. The easy way is to use the code converter in the file section. Enter your code and press the "Show 32K button." The appropriate LoROM code appears to the right, and you can find it in your game as you would any other. To adjust the code manually, just reverse the steps listed way above. Subtract $C00000 from the code, separate the first two digits, and multiply them by two. Add that to $80 and shove the result in front of the remaining four digits. If the third digit of the full code is less than 8, add 8 to it. If it is already at least 8, add one to the second digit (carrying into the first if necessary--8F + 1 = 90). For example, $C4/2104 becomes $88/A104. $C4/A104 becomes $89/A104. Use the result as you would any LoROM code.

Once you find the code, you can decipher that part of the program to figure out how it works. The rest is then the same as for NES games.

Now it's time to head over to the example and see how to cheat a whole game.

← previous
next →
loading
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.
OK
REJECT