The Gen 1 save file format: Pokémon Red, Blue & Yellow
Where everything lives in a 32 KiB Generation 1 battery save — offsets, checksums, the Pokémon struct, PC boxes and the text encoding. Verified against the pret disassemblies and against real cartridge dumps.
A Generation 1 save is 32 KiB of battery-backed SRAM, and almost all of it is empty. The parts that matter sit in three regions, guarded by three kinds of checksum, and once you know where they are the file stops being opaque.
Everything below is verified against the pret
disassemblies of Red, Blue and Yellow — ram/sram.asm and ram/wram.asm — and
then against real dumps of French and English cartridges. The tables are
generated from the same constants this site’s own parser uses to read your
uploads, so they cannot quietly drift out of date: if the parser changes, the
page changes with it.
The file
A Gen 1 cartridge has 32 KiB of SRAM, arranged as four banks of $2000 bytes. A save file is a straight linear dump of all four, in order, so an offset in the file is an offset into SRAM with no translation needed.
Three of those banks are used:
- Bank 1 holds the main game data — who you are, what you have caught, your party, and the box you currently have selected.
- Banks 2 and 3 hold the twelve PC boxes, six in each.
- Bank 0 is scratch space and holds nothing worth reading.
A file that is exactly 32,768 bytes is the normal case. Files larger than that are common and usually still fine: some cartridge dumpers read an MBC’s maximum addressable SRAM rather than the size in the cartridge header, which for Yellow’s MBC5 means 128 KiB with the real save sitting in the first 32 KiB. Trailing bytes past the first $8000 can be discarded.
Where everything lives
Addresses are absolute offsets into the save file. The symbol column gives the name the region goes by in the disassembly, which is what you will want if you are cross-referencing against pret.
| Address | Bytes | Symbol | Field |
|---|---|---|---|
| 0x2598 | 11 | wPlayerName |
Player name, terminated |
| 0x25A3 | 19 | wPokedexOwned |
Pokédex owned flags, one bit per species |
| 0x25B6 | 19 | wPokedexSeen |
Pokédex seen flags, one bit per species |
| 0x25C9 | 42 | wNumBagItems |
Bag: item count, then (item id, quantity) pairs |
| 0x25F3 | 3 | wPlayerMoney |
Money, binary-coded decimal |
| 0x2602 | 1 | wObtainedBadges |
Badges, one bit each in gym order |
| 0x2605 | 2 | wPlayerID |
Trainer ID, 16-bit, fixed at New Game |
| 0x260A | 1 | wCurMap |
Current map id |
| 0x260D | 1 | wYCoord |
Player Y position, in walking steps |
| 0x260E | 1 | wXCoord |
Player X position, in walking steps |
| 0x27E6 | 102 | wNumBoxItems |
PC item storage: count, then (item id, quantity) pairs |
| 0x284C | 1 | wCurrentBoxNum |
Selected box, in the low 7 bits, counting from 0 |
| 0x2852 | 32 | wToggleableObjectFlags |
Overworld object flags, one bit per ground item or missable sprite |
| 0x299C | 14 | wObtainedHiddenItemsFlags |
Hidden item flags, one bit per hidden spot |
| 0x29F3 | 320 | wEventFlags |
Story event flags — every trainer beaten, every one-off done |
| 0x2CED | 5 | wPlayTimeHours |
Play time: hours, maxed flag, minutes, seconds, frames |
| 0x2F2C | 404 | wPartyCount |
Party: count, species list, 6 structs, trainer names, nicknames |
| 0x30C0 | 1122 | wBoxCount |
The selected PC box, live copy |
| 0x3523 | 1 | wMainDataCheckSum |
Main checksum over 0x2598-0x3522 |
The main checksum
Bank 1 is guarded by a single byte at 0x3523. It is the one’s complement of
the sum of every byte from 0x2598 to 0x3522 inclusive, truncated to eight
bits:
sum = 0
for address in 0x2598..0x3522:
sum = (sum + byte[address]) & 0xFF
checksum = (~sum) & 0xFF
The game refuses a save whose checksum does not match, and so should you. It is also the reason you cannot edit a save by changing one byte in a hex editor and walking away: every edit inside that range has to be followed by recomputing this byte.
Note what the range covers. It starts at the player’s name and ends just before the checksum itself, which means it includes the party and the currently selected PC box — but not the other eleven boxes, which live in their own banks with their own checksums.
PC boxes
The twelve boxes are split across two banks: boxes 1 to 6 start at 0x4000,
boxes 7 to 12 at 0x6000. Each box occupies 0x462 bytes, laid out exactly
like the party region but with room for twenty Pokémon instead of six.
Each bank carries its own checksum, computed the same way as the main one, over
the bank’s six boxes and stored in the byte immediately after them — at
0x4000 + 6 × 0x462 for the first bank, and the equivalent for the second. On a
save where the player has never opened the PC, these banks are uninitialised and
their checksums will not match; treat that as “no boxes here” rather than as a
corrupt file.
There is one trap worth knowing about. The box you currently have selected
exists twice: once in its bank, and once at 0x30C0 inside bank 1. The copy in
bank 1 is the live one. The game writes the bank copy back when you switch
boxes, so on a save taken mid-session the two can disagree, and the bank copy is
the stale one. Read the active box — the number is in the low seven bits of
0x284C, plus one — from 0x30C0, and read the other eleven from their banks.
How a Pokémon is stored
Each box region and the party region share a layout: a count byte, then a list
of species indexes closed by a 0xFF terminator, then the structs, then the
original trainers’ names, then the nicknames. Each name field is eleven bytes,
filled or not.
The struct itself is 33 bytes in a box and 44 in the party. The first 33 bytes are identical; the party’s extra eleven hold the current HP, status, level and the five computed stats, all of which the game recalculates anyway. Bytes 5 and 6 are the species’ two type bytes, copied from its base stats — the values the Gen 1 type chart is indexed by.
| Offset | Bytes | Field |
|---|---|---|
| +0x00 | 1 | Species, as an internal index |
| +0x03 | 1 | Level, shared copy — what a boxed Pokémon is restored from |
| +0x08 | 4 | Move ids, one byte each |
| +0x0E | 3 | Experience, 24-bit |
| +0x11 | 10 | Stat experience: HP, Attack, Defense, Speed, Special, 16-bit each |
| +0x1B | 2 | DVs, four nibbles: Attack, Defense, Speed, Special |
| +0x21 | 1 | Level, party only — the one the game trusts |
Two details catch people out.
The species byte is not the Pokédex number. Gen 1 stores an internal
index, an ordering left over from development that has no relation to the
national dex. Mew is 0x15, Bulbasaur is 0x99. You need a lookup table in
both directions; the disassembly’s constants/pokemon_constants.asm has it.
There are two level bytes. One sits at +0x03 inside the shared 33 bytes,
and the party struct has another at +0x21. The one at +0x21 is the one the
game trusts for a Pokémon in your party; the one at +0x03 is what a boxed
Pokémon is restored from. Write both.
DVs and stat experience
Determinant values — the Gen 1 ancestor of IVs — are packed as four nibbles
across two bytes at +0x1B: Attack and Defense in the first, Speed and Special
in the second, high nibble then low. Each runs 0 to 15.
There is no HP DV stored anywhere. It is derived from the least significant bit of the other four:
hp_dv = ((atk & 1) << 3) | ((def & 1) << 2) | ((spd & 1) << 1) | (spc & 1)
Which is why a Pokémon with all four DVs at 15 also has a perfect HP DV, and why you cannot tune HP independently.
Stat experience — what later generations replaced with EVs — is five 16-bit
big-endian values at +0x11, in the order HP, Attack, Defense, Speed, Special.
Each runs to 65,535 and each contributes floor(ceil(sqrt(ev)) / 4) to the
computed stat.
Text
Gen 1 does not use ASCII. Characters are a custom encoding from
constants/charmap.asm:
0x80–0x99areAtoZ0xA0–0xB9areatoz0xF6–0xFFare0to90x7Fis a space0x50terminates a string
The rest are punctuation and the game’s own glyphs: 0xE1 and 0xE2 are the
two halves of the Pk/Mn ligature, 0xEF and 0xF5 are the male and female
symbols, and there are two distinct codes that both render as a full stop.
A name field is eleven bytes with a terminator, so ten characters is the practical maximum, and the bytes after the terminator are whatever was there before — do not assume they are zeroed.
Non-English cartridges use the same layout. A French, German or Spanish save has its regions in exactly the same places; only the text differs, because those ROMs assign accented characters to codes the English charmap does not use. Species are stored numerically, so a French save can be read by an English-language tool without any translation at all. Only names come out wrong, and only if they contain an accent.
Yellow is the same too: diffing sram.asm between the Red/Blue and Yellow
disassemblies produces nothing. A parser written for Red reads a Yellow save
without changes.
What the save does not contain
There is no field identifying which game wrote it. Nothing in a Gen 1 save says Red, Blue or Yellow. This surprises people, and it is worth stating plainly because a good deal of effort can be lost looking for it.
The usual suggestion is to infer the version from the starter, but the starter is not stored as such — only the Pokémon themselves are, and by the time a save is interesting the original starter may have been traded away, evolved, or boxed behind eleven other Pokémon. Inference from the dex flags fares no better: a save early enough to be distinctive is a save with almost nothing in it.
If you need to tell two saves apart, use the trainer’s name together with the
16-bit trainer ID at 0x2605. The ID is fixed when the game is first started
and never changes afterwards, which makes the pair a reliable identity for a
cartridge across every save it ever produces. That is what this site uses to
recognise which cartridge an upload belongs to.
Odds and ends
Money is three bytes of binary-coded decimal at 0x25F3, so 0x00 0x99
0x99 is ₽9,999 and the maximum the game will display is ₽999,999.
Badges are a single bitfield at 0x2602, one bit per badge, in gym order:
Boulder, Cascade, Thunder, Rainbow, Soul, Marsh, Volcano, Earth. Counting the
set bits gives the badge count the game shows on your trainer card.
The Pokédex is two bitfields of nineteen bytes each — owned at 0x25A3,
seen at 0x25B6. Bit n of byte m is dex number m × 8 + n + 1, least
significant bit first. Nineteen bytes gives 152 bits for 151 species, so the top
bit of the last byte is unused. A Pokémon can be seen without being owned, but
the reverse is meaningless, and the game will happily print a diploma for a save
where every owned bit is set regardless of how it got that way — which is the
whole reason all 151 on one cartridge is
possible at all, given that no single version can catch them.
Play time is five bytes at 0x2CED: hours, a flag marking the counter as
maxed out, then minutes, seconds and frames.
Your position is the map id at 0x260A and coordinates at 0x260D and
0x260E, counted in sixteen-pixel walking steps from the top-left of the
current map rather than in pixels.