Password and battery save
How a cartridge game keeps progress after power-off, either as a code the player writes down or as RAM a battery keeps alive, and how it catches a code or a save that's wrong.
A cartridge game keeps progress after power-off either as a password, which the player copies down and types back in, or in RAM that a battery on the cartridge keeps alive. The games read here range from Mega Man 2’s grid of 9 dots1, to Dragon Warrior’s ten copies of each save, each with its own CRC2.
- PasswordMega Man 2 (1988). Nine dots on a grid record the bosses beaten and the Energy Tanks.1,3,4,5,6
- Password with a check valueMetroid (1986). 24 characters of 6 bits holding 18 bytes, with an 8-bit sum and a random rotation.7,8,9,10,11,12,13Castlevania II: Simon's Quest (1987). A password keeps Simon's items, whip, and day, but not his hearts.14,15,16,17
- Battery save with a check valuePokémon Red and Blue (1996). One copy with a complemented 8-bit sum.18,19
- Battery save with copiesDragon Warrior (1986). The Famicom original gives a password to write down; the NES cartridge keeps three adventures, each written ten times over.20,21,22,23,2,24The Legend of Zelda (1986). Three files with a 16-bit sum and marker bytes; each save goes to a scratch copy first.25,26,27
#How it works
A password packs the state into as few symbols as possible. Metroid uses 6 bits a symbol, 24 symbols for 18 bytes8. A check value lets the game reject a mistyped code: Metroid stores the sum of its other bytes9. Metroid then rotates its first 16 bytes by a random count of 1-15 bits and stores the count in the password, so, as the code reads, one state can encode to more than one password9.
A battery save keeps the bytes themselves. A check value tells the game that a file has changed since it was written19. A second copy gives it one to fall back on27,2.
| Kept as | Holds | Check | On a failure | |
|---|---|---|---|---|
| Mega Man 2 | 9 dots on a 5 by 5 grid1 | E-tanks and 8 bosses beaten6 | each boss must have a dot5 | PASSWORD ERROR, back to the menu5 |
| Metroid | 24 characters of 6 bits8 | 18 bytes: items, area, gear, missiles, age7 | 8-bit sum, after a rotation9 | ERROR TRY AGAIN for 120 frames10 |
| Castlevania II: Simon’s Quest | 16 characters of 5 bits15 | level, day, laurels, garlics, items, whip14 | 16-bit sum, after an XOR and an add16 | MISS ENTRY, then the prompt again17 |
| Pokémon Red and Blue | one copy in battery RAM18 | the whole game, party, and current box18 | complemented 8-bit sum18 | “The file data is destroyed!”; no save file19 |
| The Legend of Zelda | a file and a scratch copy26 | 436 bytes per file25 | 16-bit sum and two marker bytes25 | finish the save from the copy, or erase the file27 |
| Dragon Warrior | ten copies of a 32-byte record2 | experience, gold, items, flags, name, HP, MP22 | 16-bit CRC23 | load the first good copy; with none, erase the slot2 |
#Implementations
#Mega Man 2
The grid’s top row holds the E-tank count, one dot in five cells. The other 20 cells give each of the 8 Robot Masters a “beaten” cell and a “not beaten” cell, with 4 cells left over3. The E-tank count shifts which cell is which, wrapping around the 204. The decoder accepts any grid that covers every boss with at least one of its cells5. The weapons and the three items follow from the bosses beaten6.
#Metroid
The 18 bytes hold one bit for each of 59 items, doors, and Tourian objects, the starting area, the suit bit, equipment, missiles, and Samus’s age7. To make a password, the game sums 17 bytes into the 18th, then rotates the first 16 as one 128-bit number by a random 1-15 bits9. Entering one reverses the rotation and compares the sum, and nothing else10. A password made after Mother Brain’s defeat brings her back, along with the zebetites and Tourian’s doors12.
Before any of this, the game compares the first 16 characters with NARPASSWORD00000, a code that, every frame, writes $03 to Samus’s health high byte, $FF to her equipment byte, and 5 to her missile count11. JUSTIN BAILEY ------ ------ has no such case: by the atlas’s decoding of the lines it is an ordinary password whose sum happens to match, with the bit that drops Samus’s suit set13.
#Simon’s Quest
The 16 characters hold 10 bytes: Simon’s level, the day count, the laurels and garlics, three item bytes, and the whip, then a 16-bit sum of those seven and a scramble byte14. Each character carries 5 bits and is one of 36 symbols, which by the atlas’s reading of the font’s glyphs are A-Z and 0-915. The frame counter picks one of 16 XOR tables and an add of 0-4. The first 14 characters are XORed with the table and then raised by the add, and the last two carry the choice in the clear, so one state has up to 16 passwords16. The decoder rejects a blank character, a sum that doesn’t match, or a field out of range, such as a day digit above 9, and writes MISS ENTRY17. Hearts aren’t kept: a password starts Simon with none, 48 HP, and 3 lives14.
#Pokémon Red and Blue
One copy of the game sits in battery RAM, followed by a single check byte, the complement of the bytes’ 8-bit sum18. A mismatch on loading prints “The file data is destroyed!” and the main menu then offers no save to continue19.
#The Legend of Zelda
Each of the three files carries a 16-bit sum and two marker bytes, $5A and $A525. A save goes to a scratch copy first, marked uncommitted, and is copied over the file only after its sum checks out again26. When the file screen starts, an uncommitted copy that checks out is finished, and a file that fails its markers or its sum is erased27.
#Dragon Warrior
A save is a 32-byte record with a 16-bit CRC over its first 30 bytes22,23. The game writes it 10 times; loading takes the first copy that passes and rewrites the other nine from it2. The string KEN MASUTA, kept before and after the save slots, tells it whether the RAM held anything at all; if neither copy is intact, every slot is erased24.
#History
Games
| Game | Year | How | Note |
|---|---|---|---|
| Dragon Warrior II | 1987 | the Famicom original gives a password at a king's castle; the NES cartridge records the game when the party visits a king | |
| Dragon Warrior III | 1988 | the cartridge keeps three adventure logs, written when the party visits a king | |
| Mega Man 6 | 1993 | a password grid resumes from the stage where it was given | |
| Sonic 3 & Knuckles | 1994 | six games kept on the Sonic 3 cartridge, each saved when it ends or Reset is pressed | |
| Mega Man 2 | 1988 | Password | nine dots on a grid record the bosses beaten and the Energy Tanks |
| Metroid | 1986 | Password with a check value | 24 characters of 6 bits holding 18 bytes, with an 8-bit sum and a random rotation |
| Castlevania II: Simon's Quest | 1987 | Password with a check value | a password keeps Simon's items, whip, and day, but not his hearts |
| Pokémon Red and Blue | 1996 | Battery save with a check value | one copy with a complemented 8-bit sum |
| Dragon Warrior | 1986 | Battery save with copies | the Famicom original gives a password to write down; the NES cartridge keeps three adventures, each written ten times over |
| The Legend of Zelda | 1986 | Battery save with copies | three files with a 16-bit sum and marker bytes; each save goes to a scratch copy first |
Every claim about this mechanic, by game (25)
References
- ^ abcMega Man 2's password is 9 dots on a 5 by 5 grid; the entry screen counts down from 9 as the player places dots with A and takes them back with B, and reads the password when the ninth is placed.Codelsmmega/mm2
How we know
107 LDA #$09 108 STA aobject_frameset_lower_timer
engine/password.asm lines 105–108 at 94f0bf3 · upstream ↗ 165 BEQ @skip ⋮ 168 AND #a_button 169 BEQ @b_pressed 170 LDA aobject_flag, X 171 BNE @skip 172 track_queue track_1up 173 INC aobject_flag, X 174 DEC aobject_frameset_lower_timer 175 BEQ @all_ball_set 176 BNE @skip ⋮ 178@b_pressed: 179 LDA aobject_flag, X ⋮
engine/password.asm lines 162–189 at 94f0bf3 · upstream ↗ 18password_oamycoord: 19 .BYTE $40, $40, $40, $40, $40 ⋮ 25password_oamxcoord: 26 .BYTE $41, $51, $61, $71, $81 27 .BYTE $41, $51, $61, $71, $81 28 .BYTE $41, $51, $61, $71, $81 29 .BYTE $41, $51, $61, $71, $81 30 .BYTE $41, $51, $61, $71, $81
data/password/password_oam.asm lines 18–30 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcdefDragon Warrior writes each save 10 times, one record after another, into its slot's 320 bytes; loading checks the copies in order, counts each one whose CRC fails, loads the first that passes, and rewrites all 10 from it, and if none passes the game marks the slot invalid (clearing its valid flag and mask bit, not its data) and says no deeds were recorded.Codenmikstas/dragon-warrior-disassembly
How we know
662.alias SavedGame1 $6068 ;Through $61A7. Save game slot 1. Data repeated 10 times. ⋮ 666.alias CRCFail1 $6432 ;CRC failures for save game 1.
source_files/Dragon_Warrior_Defines.asm lines 662–668 at ebe6a13 · upstream ↗ 9815LF9F9: JSR SaveData ;($FA18)Save player's data to battery backed RAM. 9816LF9FC: JSR GetCRC ;($FBE0)Get CRC for selected game data. ⋮ 9825LFA0F: JSR Save10Times ;($FAA3)Save game data 10 times accross different addresses.
source_files/Bank03.asm lines 9798–9832 at ebe6a13 · upstream ↗ 9980LFAD0: LDX #$0A ;Prepare to copy game data to 10 different locations. ⋮ 9986LFAD4: JSR CheckValidCRC ;($FB4A)Check if the CRC for the selected save game is valid. 9987LFAD7: BCS CRCCheckFail ;Is data valid? If not, branch. ⋮ 9989LFAD9: JSR LoadSavedData ;($FB6B)Load save game data into game engine registers. ⋮ 9997LFAE9: JSR Copy10Times ;($FB15)Copy of saved game data 10 times to same addresses. ⋮ 10005LFAF3: LDX SaveNumber ;Increment CRC fail counter. 10006LFAF6: INC CRCFail1,X ; ⋮ 10022LFB0A: LDA #$FF ;Indicate saved game data cannot be successfully copied.
source_files/Bank03.asm lines 9966–10035 at ebe6a13 · upstream ↗ 9320LF781: JSR Copy100Times ;($FAC1)Make up to 100 copies of saved game to validate. 9321LF784: CMP #$00 ;Is RAM for saved game valid? 9322LF786: BEQ DoneValidateSave ;If so, branch to check next saved game. ⋮ 9324LF788: LDA SaveNumber ;Saved game RAM was corrupted. Erase game. 9325LF78B: JSR ClearValidSaves ;($F80F)Clear ValidSave variable for selected game. ⋮ 9337LF79E: JSR DoDialogHiBlock ;($C7C5)Unfortunately no deeds were recorded...
source_files/Bank03.asm lines 9315–9338 at ebe6a13 · upstream ↗ 9455LF834: AND #$06 ;Clear LSB of saved game bit mask. 9456LF836: LDX #$00 ;Clear ValidSave1. 9457LF838: STX ValidSave1 ; ⋮ 9460LF83B: STA SaveBitMask ;Update valid save game bit mask.
source_files/Bank03.asm lines 9455–9460 at ebe6a13 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abMega Man 2's password holds the E-tank count and, for each of the 8 Robot Masters, whether he is beaten; a dot in the top row's first five cells gives 0-4 E-tanks, and each Robot Master has one "beaten" cell and one "not beaten" cell among the other 20, which also include 4 cells that mean nothing.Codelsmmega/mm2
How we know
1password_boss_clear_set: 2 .BYTE no_boss_clear, boss_heatman_clear, no_boss_clear, boss_quickman_clear, boss_woodman_clear ⋮ 7password_boolean: 8 .BYTE boss_clear_yes, boss_clear_yes, boss_clear_yes, boss_clear_yes, boss_clear_no
data/password/password.asm lines 1–11 at 94f0bf3 · upstream ↗ 31;boss clear flags 32 no_boss_clear = 0 33 boss_heatman_clear = 1 << 0 ⋮ 42;boss clear in password 43.ENUM 44 boss_clear_yes 45 boss_clear_no
constants/flags.asm lines 30–46 at 94f0bf3 · upstream ↗ 29 LDA z:zgot_weapon_flag 30 STA z:z00 31 EOR #%11111111 32 STA z:z01 33 CLC 34 LDA z:ze_tank 35 TAX 36 ADC #$05 37 STA z:z03 38 INC aobject_flag, X ⋮ 42 LDY password_boolean, X 43 LDA a:z00, Y ⋮
engine/show_password.asm lines 29–60 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abMega Man 2 shifts the 20 boss cells by the E-tank count; table entry i goes to cell 5 + (E-tanks + i) mod 20, wrapping from the last cell back to the first cell of the second row, so the same bosses beaten give a different grid for each E-tank count.Codelsmmega/mm2
How we know
34 LDA z:ze_tank 35 TAX 36 ADC #$05 37 STA z:z03 ⋮ 51 INY 52 CPY #$19 53 BNE @next_1 54 LDY #$05
engine/show_password.asm lines 33–57 at 94f0bf3 · upstream ↗ 202@get_e_tank: 203 STX z:z04 204 TXA 205 CLC 206 ADC #$05 207 TAX ⋮ 226 INX 227 CPX #$19 228 BNE @check_continue 229 LDX #$05
engine/password.asm lines 202–235 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcdMega Man 2 reads the E-tank count as the first dot in the top row's first four cells, or 4 if none of them holds one, without looking at the fifth; it then ORs each dotted cell's boss into a beaten byte or a not-beaten byte and accepts the password only if the two together cover all 8 bosses, else it writes PASSWORD ERROR ! and, after two waits of 125 frames, returns to the menu of START and PASSWORD.Codelsmmega/mm2revised
How we know
195@loop_6: 196 LDA aobject_flag, X 197 BNE @get_e_tank 198 INX 199 CPX #$04 200 BNE @loop_6 ⋮ 213@loop_7: 214 LDA aobject_flag, X 215 BEQ @ball_not_set 216 LDY z:z01 217 LDA password_boss_clear_set, Y 218 PHA ⋮
engine/password.asm lines 189–273 at 94f0bf3 · upstream ↗ 10 .BYTE "@START@@@" ⋮ 19 .BYTE "@PASSWORD@" ⋮ 28 .BYTE "PASSWORD@" ⋮ 37 .BYTE "ERROR@!@@@"
data/password/strings.asm lines 1–37 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcA correct Mega Man 2 password gives Mega Man the weapon of every boss in its beaten byte, Item 1 if Heat Man is beaten, Item 2 if Air Man is, and Item 3 if Flash Man is, plus its E-tank count; the password holds nothing else.Codelsmmega/mm2
How we know
275@correct: 276 LDA z:z02 277 STA z:zgot_weapon_flag 278 AND #%00000011 279 STA z:zgot_item_flag 280 LDA z:zgot_weapon_flag 281 AND #%00100000 282 LSR 283 LSR 284 LSR 285 ORA z:zgot_item_flag 286 STA z:zgot_item_flag ⋮
engine/password.asm lines 275–288 at 94f0bf3 · upstream ↗ 33 boss_heatman_clear = 1 << 0 34 boss_airman_clear = 1 << 1 ⋮ 38 boss_flashman_clear = 1 << 5
constants/flags.asm lines 30–39 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcMetroid's password holds 18 bytes; bytes 0-7 carry one bit for each of 59 items, doors, and Tourian objects collected, byte 8 the starting area (bits 0-5) and whether Samus wears her suit (bit 7), byte 9 her equipment, byte 10 her missile count, bytes 11-13 her age, byte 15 the Kraid and Ridley statue and defeat bits, byte 14 a copy of the RAM byte after the age, which nmikstas labels unused, byte 16 a scramble count, and byte 17 a check byte.Codenmikstas/metroid-disassemblyrevised
How we know
615.alias PasswordByte00 $6988 ;Stores status of items 0 thru 7. ⋮ 622.alias PasswordByte07 $698F ;Stores status of items 56 thru 58(bits 0 thru 2). 623.alias PasswordByte08 $6990 ;start location(bits 0 thru 5), Samus suit status (bit 7). 624.alias PasswordByte09 $6991 ;Stores SamusGear. 625.alias PasswordByte0A $6992 ;Stores MissileCount. ⋮ 629.alias PasswordByte0E $6996 ;Stores no data. 630.alias PasswordByte0F $6997 ;Stores Statue statuses(bits 4 thu 7). 631.alias PasswordByte10 $6998 ;Stores value RandomNumber1. 632.alias PasswordByte11 $6999 ;Stores sum of $6988 thru $6998(Checksum).
Source_Files/Metroid_Defines.asm lines 615–632 at 4270d57 · upstream ↗ 1655L8C9E:* LDA InArea ;Store InArea in bits 0 thru 5 in ⋮ 1659L8CA7: ORA #$80 ;Sets MSB of $6990 is Samus is suitless. 1660L8CA9:* STA PasswordByte08 ; 1661L8CAC: LDA SamusGear ; 1662L8CAF: STA PasswordByte09 ;SamusGear stored in $6991. 1663L8CB2: LDA MissileCount ; 1664L8CB5: STA PasswordByte0A ;MissileCount stored in $6992. ⋮ 1692L8CF2: STA PasswordByte0F ;Stores statue statuses in 4 MSB at $6997. 1693L8CF5: LDY #$03 ; 1694L8CF7:* LDA SamusAgeLo,Y ;Store SamusAgeLo in $6993, 1695L8CFA: STA PasswordByte0B,Y ;SamusAgeMid in $6994 and
Source_Files/Bank00.asm lines 1655–1697 at 4270d57 · upstream ↗ 589.alias SamusAgeLo $687D ;Low byte of Samus' age. ⋮ 592.alias SamusStat01 $6880 ;Unused memory address for storing Samus info.
Source_Files/Metroid_Defines.asm lines 589–592 at 4270d57 · upstream ↗ 1554L8BDD: LDA #$3B ; 1555L8BDF: STA $07 ;Maximum number of unique items(59 or #$3B).
Source_Files/Bank00.asm lines 1549–1560 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcMetroid writes the 18 bytes as 24 characters of 6 bits each, three bytes to every four characters, from a 64-symbol set of 0-9, A-Z, a-z, ?, and -; the entry grid's 65th symbol, a space, enters as $FF, all 8 bits set.Codenmikstas/metroid-disassembly
How we know
1884;The following code takes the 18 password bytes and converts them into 24 characters 1885;to be displayed to the player as the password. NOTE: the two MSBs will always be 0.
Source_Files/Bank00.asm lines 1884–1885 at 4270d57 · upstream ↗ 1962SixUpperBits: 1963L8F2D: LDA PasswordByte00,Y ;Uses six upper bits to create a new byte. ⋮ 1968TwoLoAndFourUp: ⋮ 1978FourLoAndTwoUp: ⋮ 1992SixLowerBits: 1993L8F5A: LDA PasswordByte00,Y ;Discard bits 6 and 7.
Source_Files/Bank00.asm lines 1962–1995 at 4270d57 · upstream ↗ 3016PasswordRow0: 3017; 0 1 2 3 4 5 6 7 8 9 A B C ⋮ 3032PasswordRow4: 3033; q r s t u v w x y z ? - Space
Source_Files/Bank00.asm lines 3016–3034 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcdeTo make a password, Metroid sums bytes 0-16 into byte 17, then rotates bytes 0-15 right as one 128-bit number, one bit at a time, as many times as byte 16 says; byte 16 is the low 4 bits of a random byte, redrawn until it is not 0.Codenmikstas/metroid-disassembly
How we know
1698L8D00:* JSR $C000 ; 1699L8D03: LDA RandomNumber1 ; 1700L8D05: AND #$0F ;Store the value of $2E at $6998 1701L8D07: BEQ - ;When any of the 4 LSB are set. (Does not 1702L8D09: STA PasswordByte10 ;allow RandomNumber1 to be a multiple of 16). 1703L8D0C: JSR PswrdChksmNScrmbl ;($8E17)Calculate checksum and scramble password.
Source_Files/Bank00.asm lines 1698–1704 at 4270d57 · upstream ↗ 1836L8E17: JSR PasswordChecksum ;($8E21)Store the combined added value of 1837L8E1A: STA PasswordByte11 ;addresses $6988 thu $6998 in $6999. 1838L8E1D: JSR PasswordScramble ;($8E2D)Scramble password. ⋮ 1844L8E25:* CLC ;Add the values at addresses 1845L8E26: ADC PasswordByte00,Y ;$6988 thru $6998 together. ⋮ 1857L8E3B:* ROR PasswordByte00,X ;Rotate right, including carry, all values in 1858L8E3E: INX ;addresses $6988 thru $6997. ⋮ 1861L8E42: ROR $00 ;Rotate right $6988 to ensure the LSB 1862L8E44: LDA $00 ;from address $6997 is rotated to the 1863L8E46: STA PasswordByte00 ;MSB of $6988. 1864L8E49: DEC $02 ; 1865L8E4B: BNE -- ;Continue rotating until $02=0.
Source_Files/Bank00.asm lines 1835–1866 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcWhen the player presses Start, Metroid rebuilds the 18 bytes from the 24 characters, rotates bytes 0-15 back left by byte 16's count, and compares their sum with byte 17; on a mismatch it plays the wrong-password sound and shows ERROR TRY AGAIN for 120 frames, and on a match it starts the game; nothing else in the password is checked.Codenmikstas/metroid-disassembly
How we know
1626L8C5E: JSR ConsolidatePassword ;($8F60)Convert password characters to password bytes. 1627L8C61: JSR ValidatePassword ;($8DDE)Verify password is correct. 1628L8C64: BCS + ;Branch if incorrect password. 1629L8C66: JMP InitializeGame ;($92D4)Preliminary housekeeping before game starts. 1630L8C69:* LDA MultiSFXFlag ; 1631L8C6C: ORA #$01 ;Set IncorrectPassword SFX flag. ⋮ 1634L8C73: STA Timer3 ;Set Timer3 time for 120 frames (2 seconds).
Source_Files/Bank00.asm lines 1625–1637 at 4270d57 · upstream ↗ 1818L8DF7:* JSR UnscramblePassword ;($8E4E)Unscramble password. 1819L8DFA: JSR PasswordChecksum ;($8E21)Calculate password checksum. 1820L8DFD: CMP PasswordByte11 ;Verify proper checksum. 1821L8E00: BEQ + ; 1822L8E02: SEC ;If password is invalid, sets carry flag.
Source_Files/Bank00.asm lines 1818–1825 at 4270d57 · upstream ↗ 1869L8E4E: LDA PasswordByte10 ;Stores random number used to scramble the password. ⋮ 1874L8E5A:* ROL PasswordByte00,X ;The following loop rolls left the first 16 bytes
Source_Files/Bank00.asm lines 1868–1882 at 4270d57 · upstream ↗ 2274L9169: LDA Timer3 ; 2275L916B: BEQ + ; 2276L916D: LDA #$59 ;
Source_Files/Bank00.asm lines 2274–2276 at 4270d57 · upstream ↗ 809;The following error message is diplayed if the player enters an incorrect password. 810; E R R O R _ T R Y _ A G A I N 811L8759: .byte $0E, $1B, $1B, $18, $1B, $FF, $1D, $1B, $22, $FF, $0A, $10, $0A, $12, $17
Source_Files/Bank00.asm lines 809–811 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-22.
Checked by a second AI model, 2026-10-25.
- ^ abMetroid compares the first 16 characters entered with NARPASSWORD00000 before anything else and, on a match, sets a flag and ignores the rest; while that flag is set, the game engine writes $03 to Samus's health high byte, $FF to her equipment byte, and 5 to her missile count, every frame.Codenmikstas/metroid-disassembly
How we know
1810L8DE5:* LDA PasswordChar00,Y ; 1811L8DE8: CMP NARPASSWORDTbl,Y ;If NARPASSWORD was entered at the 1812L8DEB: BNE + ;password screen, activate invincible 1813L8DED: DEY ;Samus, else continue to process password. ⋮ 1828;NOTE: any characters after the 16th character will be ignored if the first 16 characters 1829;match the values below. ⋮ 1832; N A R P A S S W O R D 0 0 0 0 0
Source_Files/Bank00.asm lines 1806–1833 at 4270d57 · upstream ↗ 1592LC931: lda NARPASSWORD ; 1593LC934: beq + ; 1594LC936: lda #$03 ;The following code is only accessed if 1595LC938: sta HealthHi ;NARPASSWORD has been entered at the 1596LC93B: lda #$FF ;password screen. Gives you new health, 1597LC93D: sta SamusGear ;missiles and every power-up every frame. 1598LC940: lda #$05 ; 1599LC942: sta MissileCount ;
Source_Files/Bank07.asm lines 1592–1599 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abIf Mother Brain has been destroyed when Metroid makes a password, it clears her bit and every Tourian bit in bytes 6 and 7, so the password brings back Mother Brain, the zebetites, and Tourian's missile doors.Codenmikstas/metroid-disassembly
How we know
1647L8C8A: LDA PasswordByte07 ; 1648L8C8D: AND #$04 ;Check to see if mother brain has been defeated, 1649L8C8F: BEQ + ;If so, restore mother brain, zeebetites and 1650L8C91: LDA #$00 ;all missile doors in Tourian as punishment for 1651L8C93: STA PasswordByte07 ;dying after mother brain defeated. Only reset in the 1652L8C96: LDA PasswordByte06 ;password. Continuing without resetting will not 1653L8C99: AND #$03 ;restore those items. 1654L8C9B: STA PasswordByte06 ;
Source_Files/Bank00.asm lines 1647–1654 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abComputed from the decoder's lines, the password JUSTIN BAILEY ------ ------ passes; after 255 rotations, its bytes 0-16 sum to $FF mod 256, which equals its check byte, byte 17, and byte 8's bit 7 is set, which the game loads as Samus without her suit.Codenmikstas/metroid-disassemblyrevised
How we know
2001L8F60: LDY #$00 ;Password characters #$00 and #$01. 2002L8F62: JSR SixLowerAndTwoUpper ;($8FF1) 2003L8F65: STA PasswordByte00 ;Store results.
Source_Files/Bank00.asm lines 2000–2020 at 4270d57 · upstream ↗ 2057SixLowerAndTwoUpper: 2058L8FF1: LDA PasswordChar00,Y ;Remove upper two bits and transfer ⋮ 2067FourLoNFiveThruTwo: ⋮ 2077TwoLowerAndSixLower: 2078L9011: LDA PasswordChar00,Y ;Shifts two lower bits to two higest bits
Source_Files/Bank00.asm lines 2057–2086 at 4270d57 · upstream ↗ 1869L8E4E: LDA PasswordByte10 ;Stores random number used to scramble the password.Source_Files/Bank00.asm lines 1868–1882 at 4270d57 · upstream ↗ 1712L8D1F: LDA PasswordByte08 ;If MSB in PasswordByte08 is set, 1713L8D22: AND #$80 ;Samus is not wearing her suit. 1714L8D24: BEQ + ; 1715L8D26: INY ; 1716L8D27:* STY JustInBailey ;
Source_Files/Bank00.asm lines 1712–1716 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcdSimon's Quest's password packs 10 bytes: 7 of state, the byte FoxCunning labels Simon's level, the day count in BCD, the laurel and garlic counts in 4 bits each (the encoder writes a count above 8 as 8), the bytes labeled body parts, misc items 1, and misc items 2, and the whip level; then the 16-bit sum of those 7 as a check value; then a scramble byte. Hearts are not kept: accepting a password zeroes the bytes FoxCunning labels hearts and experience, sets HP to 48 and lives to 3, and zeroes $30 and $50-$57 (labeled the map type, scene, sub-room, and scroll position), $82 (night), $84, and $85 (the time wait counter and the minute).Code“Castlevania II - Simon's Quest (USA)” · FoxCunning/Castlevania2revised
How we know
In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 4 $AF21-$AF61, EncodePassword_Compress: $8B, $83, $4C and $4D (each ANDed with $0F, then 8 if 8 or more, garlics shifted into the high nibble), $91, $92, $4A, and $0434 copied to $0520-$0526; bank 4 $AE3E-$AE5D, EncodePassword_CreateChecksum: $0520-$0526 summed with carry into $0527 (high) and $0528 (low); bank 4 $AEFB-$AF20, EncodePassword_CreateAddSub and its table: the add shifted into the high nibble of $0529, the XOR number in the low; bank 4 $AD47-$ADB5, the accepted path: $0434 kept on the stack across a JSR to $C5A1, then a JSR to $C419, $90, $4F, $33, $1E, $82, $30, $50-$57, $84, and $85 zeroed, $80 = $30, $31 = 3; bank 7 $C419-$C423, ResetHeartsAndExp: zero to $48, $49, $46, $47. We don't reproduce the bytes.
48 Edigits0011 = $46 ; $46 ⋮ 51 HeartsDigits1100 = $49 ; $49
globals.inc lines 48–51 at 2abe12c · upstream ↗ 33 CurrentLevelMapType = $30 ; $30 34 RemainingLives = $31 ; $31
globals.inc lines 33–34 at 2abe12c · upstream ↗ 52 InventoryMiscItems2 = $4A ; $4A ⋮ 54 InventoryNumLaurels = $4C ; $4C 55 InventoryNumGarlics = $4D ; $4D ⋮ 58 CurrentLevelSceneNumber = $50 ; $50 59 CurrentLevelSubRoomNumber = $51 ; $51 60 CurrentXScrollingPositionPixels = $53 ; $53 61 CurrentXScrollingPositionScreens = $54 ; $54 62 CurrentYScrollingPositionPixels_Mod240 = $56 ; $56 63 Current_WhatUnknown57 = $57 ; $57
globals.inc lines 52–63 at 2abe12c · upstream ↗ 88 CurrentHP = $80 ; $80 ⋮ 90 IsNightTime = $82 ; $82 91 CurrentDayBCD = $83 ; $83 92 CurrentTimeWaitCounter = $84 ; $84 93 CurrentMinuteBCD = $85 ; $85
globals.inc lines 88–93 at 2abe12c · upstream ↗ 102 InventoryBodyParts1 = $91 ; $91 103 InventoryMiscItems1 = $92 ; $92
globals.inc lines 102–103 at 2abe12c · upstream ↗ 258 CurrentWhipLevel = $0434 ; $0434globals.inc line 258 at 2abe12c · upstream ↗ 97 CurrentLevel = $8B ; $8Bglobals.inc line 97 at 2abe12c · upstream ↗ 301 PasswordLevel = $0520 ; $0520 302 PasswordCurrentDayBCD = $0521 ; $0521 303 PasswordLaurelsGarlics = $0522 ; $0522 304 PasswordBodyparts = $0523 ; $0523 305 PasswordMiscItems1 = $0524 ; $0524 306 PasswordMiscItems2 = $0525 ; $0525 307 PasswordWhipLevel = $0526 ; $0526 308 PasswordChecksumHi = $0527 ; $0527 309 PasswordChecksumLo = $0528 ; $0528 310 PasswordXorAdd = $0529 ; $0529
globals.inc lines 301–310 at 2abe12c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcSimon's Quest writes the 10 bytes, 80 bits, as 16 characters of 5 bits each, high bit first, so the scramble byte fills the last 8 bits; the screen draws a value n as tile n + 1 of CHR bank 16, where by the atlas's reading of the tiles 1-36 are A-Z and 0-9. Since the scramble adds up to 4 to characters 1-14, they can show all 36 (computed), and characters 15 and 16 only A-Z and 0-5. On the entry grid, pressing A on cells 0-35 enters that symbol, cells 36 and 37 step the cursor back and forward, and a later cell submits.Code“Castlevania II - Simon's Quest (USA)”revised
How we know
In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 4 $AFC7-$B0D9, EncodePassword_Convert8_to_6: $0520-$0529 shifted and masked, high bits first, into 5-bit values at $0530-$053F; bank 4 $AB75-$ABA2: the tile sent to the screen is the cursor cell ($04F4) plus 1, kept in $0F; a cleared character sends 0; bank 4 $AB3F-$AB66, A pressed: a cell below $24 enters a character, $24 and $25 decrement and increment the character position, any other advances the screen's state to the check; bank 4 $ABF9-$AC26: entering stores $0F at $0540 + position; clearing stores 0; bank 7 $C394-$C39C, before the entry screen: $10 and $11 written to $0101 and $0102, FoxCunning's Mapper1reg_reg1 and reg2, the 4 KB CHR banks; CHR ROM bank 16, tiles $01-$26: the glyphs A to Z, 0 to 9, a left arrow, and a right arrow. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcTo make a password, Simon's Quest sums the 7 state bytes into a 16-bit check value and takes a scramble from the frame counter: its low 4 bits number one of 16 tables of 14 XOR values, and its low 3 bits pick an add from 0, 1, 2, 3, 4, 1, 2, 3. After packing, characters 1-14 are XORed with the table and then have the add added; characters 15 and 16 carry the add and the table number unscrambled. Since the add follows from the table number, one state has at most 16 passwords (computed).Code“Castlevania II - Simon's Quest (USA)”
How we know
In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 4 $AE24-$AE3D, EncodePassword: compress, checksum, choose the scramble, pack, XOR, add; bank 4 $AE3E-$AE5D: 16-bit sum of $0520-$0526; bank 4 $AEFB-$AF20: FrameCounter ($1D) AND 7 indexes the 8-entry add table, AND $0F gives the XOR number; bank 4 $B205-$B327, Password_DoXorring: 16 pointers to 14-byte tables, each value below $20, XORed into $0530-$053D; bank 4 $AEE9-$AEFA, EncodePassword_DoAdding: the add added to $0530-$053D. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcOn entry Simon's Quest rejects a password with any of its 16 characters blank. Otherwise it subtracts the add from characters 1-14, XORs them, unpacks the 10 bytes, and accepts only when both bytes of the sum match the 7 state bytes again, the level is below 7, the body-parts and misc-items-2 bytes are below $80, misc items 1 is below $10, the whip level is below 5, both of the day's digits are 0-9, and laurels and garlics are each at most 8. A rejection writes MISS and ENTRY to the screen, plays sound $24, and after 128 frames brings back the ENTER YOUR PASSWORD prompt and returns to input, writing nothing to the entered characters on the way; an acceptance writes ENTRY COMPLETED.Code“Castlevania II - Simon's Quest (USA)” · FoxCunning/Castlevania2revised
How we know
In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 4 $AD16-$AD46, DecodePassword_VerifyIt: any 0 at $0540-$054F goes to the error; each value less 1 into $0530-$053F; the error sends string $59, sets the delay to $80, plays $24; bank 4 $AE15-$AE23, DecodePassword: read the scramble, subtract, XOR, unpack, check; bank 4 $AFA6-$AFC6, DecodePassword_LastByte: XOR number from $053F's low 4 bits, add from $053F bit 4 and $053E bits 0-2; bank 4 $AF94-$AFA5, DecodePassword_DoSubbing: the add subtracted from $0530-$053D; bank 4 $B0DA-$B204, DecodePassword_Convert6_to_8: the 5-bit values back into $0520-$0528; bank 4 $AE5E-$AEE0, DecodePassword_VerifyChecksum and its maxima $07, $FF, $FF, $80, $10, $80, $05: the sum recomputed and both bytes compared, level below 7, bytes 3-6 below their maxima, each day nibble below $0A, each laurel and garlic nibble below 9; on a pass, string $5A and sound $25; bank 4 $ADB6-$ADC5: count the delay down, send string $5B, set state 2; bank 4 $ADFE-$AE01, where the error jumps: increment the state ($04EF), 3 to 4; bank 4 $AAA2-$AABD, the screen's dispatch on $04EF: state 2 is $AB0C, the input handler, 3 is $AD16, the check, 4 is $ADB6, the wait. We don't reproduce the bytes.
327 PasswordInputtedCode0 = $0540 ; $0540globals.inc line 327 at 2abe12c · upstream ↗ In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 7 $C9EA-$CA03, string $59: tiles spelling MISS, then ENTRY and two punctuation tiles; bank 7 $CA04-$CA1D, string $5A: ENTRY, then COMPLETED. We don't reproduce the bytes.
1434 .word (PPU_Text_StringsList_59_bank7_PasswordError) ;C9EA (1C9EA) ([8:8][A:9]) 1435 .word (PPU_Text_StringsList_5A_bank7_EntryCompleted) ;CA04 (1CA04) ([8:8][A:9]) 1436 .word (PPU_Text_StringsList_5B_bank7_EnterYourPassword) ;CA1E (1CA1E) ([8:8][A:9])
bank_7.asm lines 1434–1436 at 2abe12c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcdePokémon Red and Blue keep one copy of the game in battery-backed cartridge RAM (the player's name, the main data, the map's sprites, the party, the current PC box, and one byte for tile animations), followed by a check byte that is the complement of the 8-bit sum of all those bytes.Codepret/pokered
How we know
12SECTION "Save Data", SRAM ⋮ 16sGameData:: 17sPlayerName:: ds NAME_LENGTH 18sMainData:: ds wMainDataEnd - wMainDataStart 19sSpriteData:: ds wSpriteDataEnd - wSpriteDataStart 20sPartyData:: ds wPartyDataEnd - wPartyDataStart 21sCurBoxData:: ds wBoxDataEnd - wBoxDataStart 22sTileAnimations:: db 23sGameDataEnd:: 24sMainDataCheckSum:: db
ram/sram.asm lines 12–24 at af51989 · upstream ↗ 290SaveGameData:: ⋮ 297CalcCheckSum: 298;Check Sum (result[1 byte] is complemented) 299 ld d, 0 300.loop 301 ld a, [hli] 302 add d 303 ld d, a 304 dec bc 305 ld a, b 306 or c 307 jr nz, .loop ⋮
engine/menus/save.asm lines 290–310 at af51989 · upstream ↗ 237 ld hl, sGameData 238 ld bc, sGameDataEnd - sGameData 239 call CalcCheckSum 240 ld [sMainDataCheckSum], a
engine/menus/save.asm lines 237–240 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcdWhen Pokémon Red and Blue load, they recompute the check byte for each of the three parts they copy (the main data twice before giving up), and on a mismatch print "The file data is destroyed!", wait 100 frames, and set the save status to 1, which the main menu treats as no save file; the saved bytes are not erased.Codepret/pokered
How we know
1TryLoadSaveFile: ⋮ 5 call LoadMainData 6 jr c, .badsum 7 call LoadCurrentBoxData 8 jr c, .badsum 9 call LoadPartyAndDexData 10 jr c, .badsum 11 ld a, $2 ; good checksum ⋮ 13.badsum ⋮ 17 ld hl, FileDataDestroyedText 18 call PrintText 19 ld c, 100 ⋮
engine/menus/save.asm lines 1–57 at af51989 · upstream ↗ 1_FileDataDestroyedText:: 2 text "The file data is" 3 line "destroyed!"
data/text/text_3.asm lines 1–3 at af51989 · upstream ↗ 32 ld a, [wSaveFileStatus] 33 cp 1 34 jr z, .noSaveFile
engine/menus/main_menu.asm lines 32–34 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^The Famicom original saves by password, the "revival spell", which the King gives the player to write down before stopping.ManualDragon Quest FC manual
How we know
ゲームをやめるときは、必ず王様に会いにいき、復活の呪文を書きとっておいてください。
section まえの続きをするには (p. 7) · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-23.
- ^The North American release saves to a battery in the cartridge, holding up to three games as Adventure Logs, recorded by visiting King Lorik in Tantegel Castle.ManualDragon Warrior Explorer's Handbook · Dragon Warrior NES manual
How we know
Pak has a battery in it. This allows it to save your game … Up to three different games can be saved at once
p. 2, Option Screen · archived copy ↗ To save your game, you must return to Tantegel Castle and visit King Lorik on the second floor.
PDF p. 15 (pp. 27-28), Visit the King · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-23.
- ^ abcDragon Warrior saves the hero as a 32-byte record in battery-backed cartridge RAM; bytes 0-1 hold experience, 2-3 gold, 4-7 the inventory, 8 the magic keys (capped at 6), 9 the herbs, 10 the equipment, 11-13 spell, player, and story flags, 14-21 the name, 22 the message speed, 23 HP, 24 MP, 25 whether HP and MP are refilled at the start, 26-29 the filler byte $C8, and 30-31 a check value.Code“Dragon Warrior (USA) (Rev 1)” · nmikstas/dragon-warrior-disassembly
How we know
In the cartridge (“Dragon Warrior (USA) (Rev 1)”): header flags 6, $12: bit 1 set, battery-backed PRG RAM at $6000-$7FFF. We don't reproduce the bytes.
9836SaveData: 9837LFA18: LDY #$00 ;Zero out index. ⋮ 9841LFA1E: INY ;Save player's experience points. ⋮ 9847LFA26: STA (GameDatPtr),Y ;Save player's gold. ⋮ 9868LFA46: CMP #$07 ;Does player have more than 6 keys? ⋮ 9871LFA4A: LDA #$06 ;6 keys max. ⋮ 9911LFA7D: LDA MessageSpeed ;Save player's message speed. ⋮ 9915LFA82: LDA HitPoints ;Save player's hit points. ⋮ 9919LFA87: LDA MagicPoints ;Save player's magic points. ⋮ 9923LFA8E: LDA StartStatus1,X ;Save player's restart status. ⋮ 9927LFA94: LDA #$C8 ; ⋮ 9931LFA9A: STA (GameDatPtr),Y ;Fill spare bytes.
source_files/Bank03.asm lines 9836–9936 at ebe6a13 · upstream ↗ 10198LFBE3: LDY #$1E ;CRC is stored in bytes 31 and 32 of saved game data.source_files/Bank03.asm lines 10196–10198 at ebe6a13 · upstream ↗ 658.alias StartStatus1 $6045 ;#$78=Full HP and MP on start, #$AB=Do not restore, Save game 1.source_files/Dragon_Warrior_Defines.asm lines 658–660 at ebe6a13 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcDragon Warrior's check value is a 16-bit CRC of the record's first 30 bytes, read from byte 29 down to byte 0, one bit at a time from the top, with the polynomial $1021 and both bytes seeded with $1D.Codenmikstas/dragon-warrior-disassembly
How we know
10209DoCRC: 10210LFBEF: LDY #$1D ;30 bytes of saved game data. ⋮ 10212LFBF1: STY CRCLB ;Seed the LFSR. 10213LFBF3: STY CRCUB ; ⋮ 10215LFBF5:* LDA (GameDatPtr),Y ;Loop until all saved data bytes are processed. 10216LFBF7: STA GenByte3C ; 10217LFBF9: JSR DoLFSR ;($FC2A)Put data through an LFSR. 10218LFBFC: DEY ;
source_files/Bank03.asm lines 10209–10220 at ebe6a13 · upstream ↗ 10265LFC2C: LDY #$08 ; 10266LFC2E:* LDA CRCUB ; 10267LFC30: EOR GenByte3C ; 10268LFC32: ASL CRCLB ; 10269LFC34: ROL CRCUB ; 10270LFC36: ASL GenByte3C ; 10271LFC38: ASL ;Some kind of linear feedback shift register I think. 10272LFC39: BCC + ;The saved data is run though this function and a 16-bit 10273LFC3B: LDA CRCLB ;CRC appears to be generated. 10274LFC3D: EOR #$21 ; 10275LFC3F: STA CRCLB ; 10276LFC41: LDA CRCUB ; ⋮
source_files/Bank03.asm lines 10261–10284 at ebe6a13 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abDragon Warrior marks its battery RAM as initialized with the 10 ASCII bytes KEN MASUTA, written both before and after the three save slots; before showing the saved games it checks the copy after the slots and then the one before, and only if neither matches does it erase all three slots, then rewrites both copies.Codenmikstas/dragon-warrior-disassembly
How we know
9242GetValidSaves: 9243LF6F4: LDX #$09 ;Prepare to check for Ken Masuta's name in battery backed RAM. 9244LF6F6:* LDA KenMasuta1,X ; 9245LF6F9: CMP KenMasutaTbl,X ;Check if Ken's name is intact in the battery backed RAM. 9246LF6FC: BNE InitSaves ;Is the name correct? If not, branch to invalidae all saved games. ⋮ 9254LF706:* LDA KenMasuta2,X ; ⋮ 9257LF70C: BNE ClearSaveGameRAM ;If not, RAM values are corrupt. Branch to rease saved games. ⋮ 9269LF71A:* STA SavedGame1,X ;Clear first 256 bytes of save game data for all slots. ⋮ 9295LF753: LDX #$09 ;Write Ken Masuta's name to 2 different RAM locations.
source_files/Bank03.asm lines 9242–9300 at ebe6a13 · upstream ↗ 10321KenMasutaTbl: 10322; K E N _ M A S U T A 10323LFC76: .byte $4B, $45, $4E, $20, $4D, $41, $53, $55, $54, $41
source_files/Bank03.asm lines 10321–10323 at ebe6a13 · upstream ↗ 657.alias KenMasuta2 $603B ;Through $6044. Stores Ken Masuta's name. ⋮ 665.alias KenMasuta1 $6428 ;Through $6431. Stores Ken Masuta's name.
source_files/Dragon_Warrior_Defines.asm lines 657–665 at ebe6a13 · upstream ↗ 9477LF853: BRK ;Load BG and sprite palettes for selecting saved game. ⋮ 9480LF856: JSR GetValidSaves ;($F6F4)Get valid save game slots.
source_files/Bank03.asm lines 9470–9480 at ebe6a13 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-22.
Checked by a second AI model, 2026-10-25.
- ^ abcdThe Legend of Zelda keeps three save files in battery-backed cartridge RAM; each holds an 8-byte name, a 40-byte item block, 384 bytes of world flags, and four single bytes (whether the slot is in use, one unlabeled byte, the death count, and the quest), with a 16-bit checksum that is the plain sum of those 436 bytes, and, kept apart and outside the sum, two marker bytes, $5A and $A5.Code“Legend of Zelda, The (USA) (Rev 1)” · aldonunez/zelda1-disassemblyrevised
How we know
In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): header flags 6, $12: bit 1 set, battery-backed PRG RAM at $6000-$7FFF. We don't reproduce the bytes.
301SaveRamBegin := $6001 302SaveFileAName0 := $6002 ⋮ 305SaveFileAItems0 := $601A ⋮ 308SaveFileAWorldFlags0 := $6092 ⋮ 320SaveFileOpenMarkers := $651E 321SaveFileCloseMarkers := $6521 322FileAChecksums := $6524 323IsSaveFileBCommitted := $652A
src/Variables.inc lines 301–323 at 50a1c86 · upstream ↗ 2321CalculateFileAChecksum: ⋮ 2323 STA $0E 2324 STA $0F 2325 LDY #$07 ; Sum the name (8 bytes). ⋮ 2329 JSR AddATo0F0E ⋮ 2332 LDY #$27 ; Add the Items block ($28 bytes) to [$0F:0E]. ⋮ 2336 JSR AddATo0F0E ⋮ 2343 LDY #$00 ; Add World Flags ($180 bytes) to [$0F:0E]. ⋮ 2347 JSR AddATo0F0E ⋮ 2357 LDA ($06), Y ; IsSaveSlotActive 2358 JSR AddATo0F0E 2359 LDA ($08), Y ; TODO: Add byte at [[$08:09]] to [$0F:0E]. ⋮
src/Z_02.asm lines 2319–2372 at 50a1c86 · upstream ↗ 2289 LDA SaveFileOpenMarkers, Y ; Are the static markers intact? 2290 CMP #$5A 2291 BNE @FormatA 2292 LDA SaveFileCloseMarkers, Y 2293 CMP #$A5
src/Z_02.asm lines 2289–2295 at 50a1c86 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abcThe Legend of Zelda saves in two steps; it first writes the whole file to a second copy, file B, sums it, stores that sum, and marks B uncommitted, and on the next step it sums B again and, if the sums agree, clears file A's markers, copies B over A, writes A's markers and sum, and marks B committed.Codealdonunez/zelda1-disassembly
How we know
2944UpdateModeDSave_Sub0: 2945 ; Initialize file B, and copy profile to it. 2946 ; Calculate and store file B checksum. 2947 ; Mark file B uncommitted. 2948 JSR FetchFileBAddressSet ⋮ 2950 JSR FetchFileBAddressSet ⋮ 2959 LDY CurSaveSlot ⋮ 2965 LDY CurSaveSlot ⋮ 3011 JSR FetchFileBAddressSet ⋮ 3016UpdateModeDSave_Sub1: 3017 LDY CurSaveSlot 3018 LDA IsSaveFileBCommitted, Y ⋮
src/Z_02.asm lines 2944–3046 at 50a1c86 · upstream ↗ 3048CopyFileBToFileA: 3049 LDY CurSaveSlot 3050 LDA #$00 ; Reset the save file markers. 3051 STA SaveFileOpenMarkers, Y 3052 STA SaveFileCloseMarkers, Y ⋮ 3056 LDA #$00 ⋮ 3084 LDY CurSaveSlot ⋮ 3124 LDY CurSaveSlot 3125 LDA #$5A ; Write the save file markers. 3126 STA SaveFileOpenMarkers, Y ⋮ 3128 STA SaveFileCloseMarkers, Y 3129 TYA ; Copy the checksum from file B to file A. ⋮
src/Z_02.asm lines 3048–3140 at 50a1c86 · upstream ↗ 1350SaveFileBAddressSets: 1351 .BYTE $98, $68, $10, $69, $80, $68, $90, $6D
src/Z_02.asm lines 1350–1360 at 50a1c86 · upstream ↗ 325LevelBlockAttrsA := $687Esrc/Variables.inc line 325 at 50a1c86 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abcdWhen its title demo or its file select screen starts, The Legend of Zelda checks each of the three slots; a file B still marked uncommitted whose sum matches is copied over file A, finishing a save that was cut off, and a file A whose markers are not $5A and $A5 or whose sum doesn't match is formatted, its name set to spaces and every other byte to 0.Codealdonunez/zelda1-disassembly
How we know
2253 ; For each save slot: 2254 ; If file B is uncommitted and valid, then 2255 ; Copy file B to file A (also marks file B committed) 2256 ; If file A's static markers are wrong or file is invalid, then 2257 ; Format file A ⋮ 2286 JSR FetchFileAAddressSet ⋮ 2291 BNE @FormatA ⋮ 2298 LDA FileAChecksums, Y ; Does the checksum match? 2299 CMP $0E 2300 BNE @FormatA ⋮ 2302 LDA FileAChecksums, Y ⋮ 2306@FormatA: ⋮
src/Z_02.asm lines 2252–2316 at 50a1c86 · upstream ↗ 2374FormatFileA: 2375 LDY #$07 2376 LDA #$24 ; Make the name 8 spaces. ⋮ 2382 LDY #$27 ; Reset the file's Items block. 2383 LDA #$00 ⋮ 2393 LDY #$00 ; Reset World Flags ($180 bytes) at [$02:03]. ⋮ 2396 LDA #$00 ⋮ 2407 LDA #$00 2408 STA ($06), Y ; Reset the file's IsSaveSlotActive.
src/Z_02.asm lines 2374–2410 at 50a1c86 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
Sources
Code
- lsmmega. 2026. “mm2: Mega Man 2 disassembly (lsmmega/mm2).” Commit 94f0bf3. lsmmega/mm2 @ 94f0bf3 · licence, all uses
- nmikstas. 2023. “dragon-warrior-disassembly: NES Dragon Warrior software disassembly.” Commit ebe6a13. nmikstas/dragon-warrior-disassembly @ ebe6a13 · licence, all uses
- nmikstas and Kent Hansen. 2025. “metroid-disassembly: Metroid software disassembly.” Commit 4270d57. nmikstas/metroid-disassembly @ 4270d57 · licence, all uses
- pret contributors. 2026. “pokered: disassembly of Pokémon Red and Blue.” pret. Commit af51989. pret/pokered @ af51989 · licence, all uses
- Núñez, Aldo. 2021. “zelda1-disassembly: A complete disassembly of The Legend of Zelda.” Commit 50a1c86. aldonunez/zelda1-disassembly @ 50a1c86 · licence, all uses
- 1988. “Castlevania II - Simon's Quest (USA).” · licence, all uses
- FoxCunning. 2022. “Castlevania 2 - Bloodlust: a full disassembly and hack of Castlevania II: Simon's Quest.” Commit 2abe12c. FoxCunning/Castlevania2 @ 2abe12c · licence, all uses
- n.d. “Legend of Zelda, The (USA) (Rev 1).” · licence, all uses
- 1989. “Dragon Warrior (USA) (Rev 1).” · licence, all uses