Written by:
Brian Maxwell / Anus Pompous
Anus Pee's goddamn home page!
E-Mail AnusP!
J2e translations
E-Mail J2E Translations!
Ported and Fixed to HTML by: CaTaclysmX
CaTaclysmX's Page of Emulation
Email CaTaclysmX!
Get the text version HERE!
==================
TABLE OF CONTENTS
==================
1- Introduction
2- How Text is Normally Stored
3- Headers
4- Pointer Tables
5- Moving Text in SNES Roms
6- Physical Rom Expansion
7- Expanding text past its bank
8- Conclusion
=======================
SECTION 1 INTRODUCTION
=======================
1.0 General Stuff about this document
This document was created to help people who wish to
learn about pointer tables and SNES rom expansion. This
document may be very confusing but I tried to keep it as
simple as possible! heh. I wrote in in one night! So I'll
probably have to update it later to fix spelling errors,
or make things easier to understand... but I'm nothing
more than a lazy bastard, so my hacks come first! Anyways,
if you do not know anything about rom-hacking, or you don't
know much about it, then LEARN and get some experience!
the only program you'll need to do the following is a hex
editor. I recommend "Hex
Workshop"! I
also tried to write this document to be as universal as
possible, so not every rom will be modified or expanded
in the following ways. So if you have problems with this
document, then you're either hacking an EVIL rom, or
something I haven't seen yet. Or I might not have gotten
my point accross.. Please, tell me how good this document
is! I beg you!
1.1 History
version 1.0
(HTML)
Ported to HTML by CataclysmX
======================================
SECTION 2 HOW TEXT IS NORMALLY STORED
======================================
2.0 Variable Length Text
In rom's text is usually stored in clumps of text strings.
For instance, one text string will appear after another,
and are usually separated by a hex value which signifies
the end of a string (not a line break!). Now the text in
these clumps of text strings (I like to call them "text
blocks") won't nessessarily have the text in the
order that it appears in the game. In NES roms this is
how all of the text is usually stored, with a "standard
pointer table system". But in SNES roms, I have
found other ways in which text is stored; Some times text
will be stored in text blocks as mentioned above, but
will include some coding in between each string instead
of a standard hex to signify the end of a line. These
text blocks usually don't have pointer tables and you
should be able to change the lengths of individual
strings without any problems! The only downfall to text
stored like this is the fact that it makes it harder to
dump text from it to get it translated. Examples of text
that's stored like this are the Romancing Saga games.
2.1 Constant Length text
One other way that some text is sometimes stored in SNES
roms is in a "constant length" format. This is
usually how monster names, items, ect... are stored in
RPGs. The Final Fantasy games store that kind of stuff in
that format. What Constant Length text is; It's a bunch
of text (items) that have a certain length and are not
separated by hex values which signify the end of a string.
They run right into one another... For example, the Items
in Final Fantasy 4 are 9 characters long, and they follow
one another like this:
Tent FenixDownPotion BlackSwrdIronArrow
as you can see there is no specific hex value separating
them. Which means that you can use the extra space as you
wish! Because if you look there are still 5 spaces to use
for Tent, so you can make that name even longer of you
wish! While this may be good news for some things, You
wont be able to exceed the maximum amount of spaces used
for each item. The only way to increase the amount of
letters you can use for Constant Length text is to learn
ASM!
2.2 Text that's just floating around
And finally, sometimes in SNES roms, there is just text
floating around in the rom on its own, not in any
specific "Text Blocks". The only way to expand
these out is to move'em to somewhere in the rom where
there is room to epand them out! (explained in more
detail later on... section 5)
2.3 Something else you should know about the way SNES
stores text.
Sometimes there are Text Blocks in the rom which do not
use pointer tables. These can just simply be expanded out
as you wish without any trouble just by moving the hex
values which signify the end of a string. This is similar
to the "RS" text blocks with the coding in
between each string. just move the coding to fit text
into rom. But one thing you should know is that there is
sometimes text stored in the rom (in text blocks) that
have to be expanded out in a similar mannar that the text
floating around has to be. Basically this type of text is
text just "floating around" in the rom, exept
they follow one another like text would in a standard
text block.
==================
SECTION 3 HEADERS
==================
3.0 NES Headers
The headers in NES roms are in the first line of an NES
rom in a hex editor. the fist 16 bytes of the rom is its
header. In other words the header covers "10"
hex bytes. This is an important number to remember when
editing pointer tables in NES roms.
the header usually looks something like this:
4E45 531A 1000 1300 0000 0000 0000 0000
You'll notice that the first three bytes are the ASCII
standard for "NES"! Other info is stored here
such as the mapper number, ect....
3.1 SNES Headers
The header in SNES roms is remarkably bigger than in NES
roms. It covers 512 bytes. Or "200" hex bytes.
This is also another important number to remember. Not as
important for pointer tables though, but it is important
for moving text blocks and stuff!
the header in an SNES rom looks similar to this:
8000000000000000AABB040000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
The information here is not really important.
But if you're rom does not have a header, then ADD ONE!
(This is sometime the cause of roms not working in some
emulators)
To add a header to it, just copy a header from any SNES
game that has one, and then "Insert" the copied
header into the rom.
=========================
SECTION 4 POINTER TABLES
=========================
4.0 NES Pointer Tables
To find a pointer table for the text in your rom, it is
nessessary that you know where the text is in the rom,
what hex signifies the end of a line, and by knowing
these you can then find the beginning of the text block.
Once you find the beginning of the text block the pointer
table should be IMMEDIATELY before the text! It will look
like it has a pattern to it. Figuring out the pattern is
mostly up to you, but here is pretty much how you figure
out how it works. Take an address from the beginning of a
line. (An example would be 012D63) and knock off the all
extra letters except for the last 4 digits making it 2D63.
Pointer tables store addresses in pairs so 2 hex values
are needed... break up 2D63 into pairs and you got 2 hex
values.. 2D, and 63! Now before you break up the hex
values, you gotta subtract the header from the address.
Since the NES header is 10 hex bytes, subtract 2D63 by 10
making it 2D53. Now break this up into pairs making it 2D
53, and then re-arrange it backwards! (thats how roms
store addresses. so 2D 53, becomes 53 2D. This will tell
you one of the hex values in each pointer in the pointer
tables. You should be able to find 53 in there, but 2D
might be something else.. So you're actually looking for
53xx (where xx is unknown). That's up to you to figure
out!
an example of a pointer table followed by text in an NES
rom:
019D30: 4D76 00F8 349D 3B9D 419D 449D 499D 4D9D
019D40: 529D 569D E5E3 F6CD 4ADA 70F8 F9FA FBF0
019D50: 704C FE70 4BDD CEF3 705C F64D 704C F6CF
019D60: CE70 F5DD CB70 4BF0 DDF1 F2DD F370 83B7
Explanation: Well, hex "70" signifies the end
of a string so using that you find the begining of the
text block which is at hex 019D44, and so everything
before that is the pointer table! You'll notice that 9D
repeats alot in the pointer table. Well, that is your
unknown which you gotta figure out on your own!
4.1 SNES Pointer Tables
SNES pointer tables work in the same manner, except you
don't subtract the header from it. But you gotta watch
out, because sometimes you might get an evil rom in which
you GOTTA subtract something, but thats very rare and
easy to deal with once you get the hang of it! Now also
keep in mind that sometimes text in SNES roms don't use a
pointer table(Romancing SaGA). So if you can't find one
before the text, then just experiment! Try changing the
lengths of the strings by moving around the hex that
signifies the end of a string and see if it works! But if
it doesn't work, and there's no pointer table, then you're
gonna have to learn how to move text within the rom! (explained
in section 5)
===================================
SECTION 5 MOVING TEXT IN SNES ROMS
===================================
5.0 Moving Text Within Banks
Now this is more heavy stuff! You might have to do this
if the text you have doesn't have a pointer table, and
wont expand just by moving the hex to signify the end of
a text string. You will also have to do this to expand
text that's just floating around in the rom. Most of the
time this text is moved within Banks. What's a bank? well...
time for my explanation. A bank is a part of the rom in
which info is stored. One bank in a low-rom is 32KB (8000
hex bytes) and in a high-rom its 64KB (10000 hex bytes).
For instince, the adress $000200 to $0081FF is the first
bank within a low-rom and $008200 to $0101FF is the 2nd
bank, ect... And in a high-rom $000200 to $0101FF is the
first bank and $020200 to $0301FF is the 2nd bank, ect...
These addresses have the $200 header included if you
notice! Oh, and did I forget to mention, the "$"
before the address signifies that I'm talking about hex
values! Anyways... Most of the time text that's just
floating there, or whatever can only be moved within the
bank that it's located in. To do this you gotta start
converting the address into a pointer to that address you
can find! First, lets take some text from FF4 that's on
its own (not in any specific text block) at the address
09DEC6. Now subtract the header from this address ($200
in SNES roms, if the game has a header). So $09DEC6 - $200
= $09DCC6. Now, since you are just moving one small thing,
chances are, it can only be moved within that bank! Which
means that it has to be moved within $098000 to $09FFFF (without
the header, ofcourse. also note that FF4 is a low-rom).
Now the next step to do is to get rid of the 09 before
the rest of the address, since jumps within banks are
stored as 2 hex bytes. So 09DCC6 becomes DCC6. Now split
it up and make it backwards so it becomes C6DC, and
search for that number within the bank, and hopefully you'll
find the pointer!
Another Note: The address you are searching for must
always be between 8000 to FFFF in a low-rom, so if you're
looking up a pointer for text at 0928B0, subtract the
header, knock off the extra 09 (or whatever that may be),
which makes it 26B0. Now before you split it up and make
it backwards, you gotta att $8000 to it, to make the
address between 8000 to FFFF, so $26B0 + $8000 becomes $A6B0.
You then re-arrange it as B0A6 and search for that! But
in a high-rom, the address can be anywhere between 0000
and FFFF since the banks are 64KB instead of 32KB.
5.1 Moving Large Text Blocks (and other stuff) To
Different Banks!
Usually Large Blocks of text will have pointers that will
anable you to move text to anywhere in the rom! This is
where physical expansion comes in handy! (explained in
section 6) What you will have to do is move text to a
place where there is enough room to expand it out. First
find the place where your text begins. (you'll have to
move text and its pointer tables seperately... This may
also apply for some text just floating in the rom, but
they usally use pointers within banks to point to them.)
Moving these is basically done in the same mannor as
above, exept you gotta figure out what bank its in. The
first thing to do is subtract the header, and this
following chart shows the conversion between the actual
address and the way the SNES will read the address.
this chart is for low-roms:
HEX |
Low-ROM SNES |
|
---|---|---|
000000-007FFF |
= |
008000-00FFFF |
I'm sure you see the pattern now. So lets say you
have a text block located at $080600. Subtract the header,
so it becomes $080400, and then look it up on the chart
and find its new address. so $080400 is actually $108400.
Now split it up into pairs -> 10 84 00, and re-arrange
them backwards -> 008410. Now you'll have to search
for that, and remember, it might appear more than once in
the rom, so the best thing to do change all of these
addresses that appear in the rom to the new one.
A little hint: These kind of just USUALLY have "BF"
before them, so 008410, might look like BF008410.
Now for high-roms since the banks are in 64KB blocks the
way the snes addresses them is different. They don't have
to be between the 8000-FFFF crap! It just adds up like a
normal adress exept it starts at C00000. So really, all
you gotta do is add $C00000 to the hex address to get the
High-rom SNES address. For example, take hex $1AE380,
subtract the header so it becomes $1AE180 and now add $C00000
so it becomes $DAE180. And there you go! You got yourself
your pointer!
======================================
SECTION 6 PHYSICAL SNES ROM EXPANSION
======================================
Now for the easy part! In SNES roms, all you gotta do to
make the rom bigger, is just add more space to it! Of
course the space that you add HAS to be a multiple of 32KB,
or $8000 hex bytes, or 1 bank.
But the roms are usually more stable if you keep them at
a muliple of 4mbits.
below is a small chart which shows stable file sizes to
keep your rom at:
(the following hex addresses include the $200 header)
MBITs |
HEX BYTES |
~ SIZE |
---|---|---|
4mbit |
$080200 |
0.5MB |
yada yada yada... I'm sure you see the
pattern...
well, that about does it! Don't ask me how to expand NES
roms, because I don't know how, and from what I hear it's
next to impossible!
=======================================
SECTION 7 EXPANDING TEXT PAST ITS BANK
=======================================
What do I have to say about this? Well, unless you're
prepared to do some ASM modifications, don't expand text
past the bank that its in. What I mean by this is, if you
have a low rom and you're expanding text, you can't have
it exceed the 32KB that's allocated for the bank, or 64KB
for high-roms. What tends to happen is the text that runs
spills into the next bank tends not to be displayed on
the screen. Now I'm not sure that this is the case with
some roms, but I'm suspecting that it is because this has
happened to us in our FF4 translation. Now there is
another way to get around the problem, and that's to
limit the player to using ZSNES 2.95 because of a bug in
it! But I would not recommend using that as an
alternative, because not everyone will want to use that
old version of ZSNES.
=====================
SECTION 8 CONCLUSION
=====================
Wow! I wrote all this in one night!?! Yep! Now I'm damn
tired! Anyways, Most of the stuff in this document covers
stuff on SNES roms, so if you're having trouble with NES
roms, please don't contact me, because I probably won't
know about it! I only know how to find NES pointer tables,
and that's it! But SNES is a different story! I am
constantly learning more and more, and so someday this
document will probably be even better! But for now, it
remains as it is.
I would like to thank the following people:
P-Funk: |
For helping me out with moving stuff within a rom |
Dark Force: |
For helping me out with some technical stuff as well |
Necrosaro: |
For creating his program to save time on adding up all of FF4's pointers!! (that would have taken a loooong time without him!) |
CataclysmX: |
For originally porting this document into HTML and other stuff! |
Any questions/comments? Send away to AnusP!
Any HTML comments or flames Send away to CaTaclysmX!
***Copyright Issues***
Anyone who distributes this file must not modify it in
any way, without prior consent from the author. They must
also have a link to J2E translations and Anus P's home
page at the top or bottom of the page. Thank you for your
cooperation.
J2E Translations! (http://www.members.aol.com/j2etrans/index.html)
Anus P. (C) 1998