-------------------------------------------------------------------------------
| Dragon Warrior (NES) SRAM Document 1.0
| by John David Ratliff
|
| The most recent version of this guide can always be found at
| http://games.technoplaza.net/dwsrame/sram-doc.txt
|
| Copyright (C) 2007 emuWorks (http://games.technoplaza.net/)
|   Permission is granted to copy, distribute and/or modify this document
|   under the terms of the GNU Free Documentation License, Version 1.2
|   or any later version published by the Free Software Foundation;
|   with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
|   Texts.  A copy of the license can be found at
|   http://www.gnu.org/licenses/fdl.html
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
| Table of Contents
-------------------------------------------------------------------------------

 - 1.0 Introduction
 - 2.0 Copyright Notice
 - 3.0 Revision History
 - 4.0 The Dragon Warrior SRAM
   - 4.1 SRAM Basics
   - 4.2 SRAM Offsets
   - 4.3 The Sanity Algorithm
   - 4.4 Checksum Bypass Using a Game Genie
 - 5.0 dwsrame - The Dragon Warrior (NES) SRAM Editor
 - 6.0 Contact Information

-------------------------------------------------------------------------------
| 1.0 Introduction
-------------------------------------------------------------------------------

 This document is a guide to the SRAM format used by Dragon Warrior for the
 original Nintendo (NES). SRAM (short for save random access memory, and has
 many other names and acronyms) was the format for saving data in most NES
 cartridge games including Dragon Warrior.

 SRAM was an area of memory that was supplied power by an internal cartridge
 battery. It's purpose was to preserve information even when the game was not
 running. In this manner, game progress could be preserved even when the system
 was not active.

 SRAM is not the same as emulator save states. SRAM was internal to the game
 cartridge and thus the format is applicable to any NES emulator (and probably
 all NES copiers as well).

 This document aims to discuss the data format used in SRAM to store game
 progress.

 There have been many adaptations, remakes, and translations of Dragon Warrior
 over the years. To be clear, this guide covers the SRAM used by the original
 Dragon Warrior for the NES (the original English translation of the original
 Dragon Quest for the Famicom) released by Enix in 1989.

-------------------------------------------------------------------------------
| 2.0 Copyright Notice
-------------------------------------------------------------------------------

 This document is Copyright (C) 2007 emuWorks (http://games.technoplaza.net/)
   Permission is granted to copy, distribute and/or modify this document
   under the terms of the GNU Free Documentation License, Version 1.2
   or any later version published by the Free Software Foundation;
   with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
   Texts.  A copy of the license can be found at
   http://www.gnu.org/licenses/fdl.html

 Basically, it is free documentation in much the same way software under the
 GNU General Public License is free software. You can modify it, redistribute
 it, sell it, publish it, etc.

-------------------------------------------------------------------------------
| 3.0 Revision History
-------------------------------------------------------------------------------

 Version 1.0 - Friday, February 2, 2007
   - First Public Release

-------------------------------------------------------------------------------
| 4.0 Dragon Warrior SRAM
-------------------------------------------------------------------------------

 This section details the SRAM format used by Dragon Warrior (NES).

-------------------------------------------------------------------------------
| 4.1 SRAM Basics
-------------------------------------------------------------------------------

 The Dragon Warrior cartridge had an SRAM of 0x2000 (8192 decimal) bytes. This
 was the standard for NES cartridges of the time.

 There were three possible save slots available in the game. Each of these
 slots used 0x140 bytes of SRAM, though in reality it is actually just 0x20
 bytes repeated 7 times.

 Because the SRAM was battery backed, and the battery will eventually die, the
 game also stored certain data to act as a check on the sanity of the
 preserved data. Two checks were used. The first was the data replication. The
 0x20 bytes of game data are replicated 7 times. Secondly, the 0x20 bytes of
 data also have some embedded sanity data, which I will call the checksum.

 Finally, there are 4 bytes in the SRAM that determines what save slots are in
 use.

 The three games begin at offset 0x68 from the start of the SRAM. From there,
 the three game's 0x140 bytes of data are stored sequentially. The 4 bytes of
 save slot usage start at offset 0x35 from the start of SRAM.

-------------------------------------------------------------------------------
| 4.2 SRAM Offsets
-------------------------------------------------------------------------------

 The following are the known offsets within the game data. They will be
 presented relative to the start of a particular game slot rather than from
 the start of SRAM. This means an offset of 0 for the first game is actually
 at the SRAM position 0x68. For the duplication, this means it is also as
 0x88, 0xA8, and so on for all 6 duplicate sets.

 00-01: Hero's Experience
 02-03: Hero's Gold

   Both of these values are little-endian 16-bit unsigned values. This means
   they can range from 0 - 65535. It also means the bytes when viewed as hex
   should be reversed. ex: 34245 decimal = 85C5 hex = C585 little-endian hex.

 04-07: Hero's Inventory

   The hero's inventory is comprised of at most 8 items. Because of the
   limited number of possible items, each item can be represented in a
   half-byte (4 bits). This means each byte can represent two numbers. The
   item values are as follows:

   0: No Item
   1: Torch
   2: Fairy Water
   3: Wings
   4: Dragon's Scale
   5: Fairy Flute
   6: Fighter's Ring
   7: Erdrick's Token
   8: Gwaelin's Love
   9: Cursed Belt
   A: Silver Harp
   B: Death Necklace
   C: Stones of Sunlight
   D: Staff of Rain
   E: Rainbow Drop
   F: (unused) displays current number of Herbs, but you cannot use this

   So, if 04 had the value E3, the hero will have the Rainbow Drop and a set
   of Wings in his inventory.

 08: Hero's Keys
 09: Hero's Herbs

   These two bytes tell how many of these particular items the hero has. Valid
   values are 0 - 6. Using values outside the valid range is untested.

 0A: Equipment Byte

   The equipment byte detemines the hero's weaponry. To decide what the hero
   is equipped with, you simply need to add the possible values together.

   Weapons:
     Bamboo Pole:      0x20
     Club:             0x40
     Copper Sword:     0x60
     Hand Axe:         0x80
     Broad Sword:      0xA0
     Flame Sword:      0xC0
     Erdrick's Sword:  0xE0

   Armor:
     Clothes:          0x04
     Leather Armor:    0x08
     Chain Mail:       0x0C
     Half Plate Armor: 0x10
     Full Plate Armor: 0x14
     Magic Armor:      0x18
     Erdrick's Armor:  0x1C

   Shields:
     Small Shield:     0x01
     Large Shield:     0x02
     Silver Shield:    0x03

   So, if you want the best equipment possible, add the value of Erdrick's
   Sword (0xE0), Erdrick's Armor (0x1C), and the Silver Shield (0x3) to get an
   equipment byte value of 0xFF.

 0B: Quest byte 1
 0C: Quest byte 2
 0D: Quest byte 3

   Quest bytes determine whether certain things have happened in the game or
   not. Things not covered by the quest bytes are usually determined by the
   hero's inventory. For example, if you have the staff of rain, the old man
   who gives it to you will tell you to go away.

   The quest bytes use individual bits to determine various quest markers. The
   bits not documented are not known to do anything.

   Byte 1:
     bit 2 - Charlock Hidden Stairs Revealed
     bit 3 - Rainbow Bridge Built
     bit 4 - Wearing Dragon's Scale
     bit 5 - Wearing Fighter's Ring
     bit 6 - Wearing Cursed Belt
     bit 7 - Wearing Death Necklace

   Byte 2:
     bit 0 - Gwaelin Rescued (in Hero's arms)
     bit 1 - Gwealin on Throne (bits 1 and 0 should be mutually exclusive)
     bit 3 - Started Quest

   Byte 3:
     bit 1 - Golem Killed
     bit 2 - Dragonlord Killed
     bit 6 - Green Dragon Guarding Princess Gwaelin Killed

 0E-15: Hero's Name

   The hero's name is stored in a very odd manner. The first four characters
   0E-11 are the first four characters of the name, but they are stored in
   reverse order. In other words, if your characters name is 'Loki', it will
   be stored ikoL.

   The second four characters 12-15 are the second four characters of the
   name, and they too are stored in reverse order.

   Here are the values for the Dragon Warrior alphabet.

   0x00 - 0x09 : The numbers 0-9
   0x0A - 0x23 : The lowercase letters 'a' - 'z'
   0x24 - 0x3D : The uppercase letters 'A' - 'Z'
   0x40        : The apostrophe ' character
   0x47        : The period . character
   0x48        : The comma , character
   0x49        : The dash - character
   0x4B        : The question mark ? character
   0x4C        : The exclamation point ! character
   0x4E        : The close paren ) character
   0x4F        : The open paren ( character
   0x60        : The space ' ' character

   These are the only valid characters accepted by the name input screen.
   Using other values may produce other symbols in the name, though this is
   untested.

 16: Message Speed

   This offset determines the message speed for the game. Valid values are 0
   for fast, 1 for normal, and 2 for slow.

 17: Hero's HP
 18: Hero's MP

   The HP and MP are the current HP and MP for the hero. The valid range is
   0 - 255.

 19:    (unused) always AB
 1A-1D: (unused) always C8

 1E-1F: Checksum

   The checksum is a two-byte value. It will be described in the next section.

 Finally, the four bytes that determine game slot usage are as follows:

 0x35, 0x36, and 0x37 - 0 if the slot is unused, C8 if it is
 0x38 - Three bits determine game usage
   bit 0 - slot 1
   bit 1 - slot 2
   bit 2 - slot 3

 So, if all three slots are in use, you will see 0xC8 0xC8 0xC8 0x07 for these
 four bytes. These offsets are relative to the start of SRAM, not the start of
 game data.

-------------------------------------------------------------------------------
| 4.3 The Sanity Algorithm
-------------------------------------------------------------------------------

 As mentioned earlier, the game needs to ensure the data stored in the SRAM is
 still valid. To do this, it uses data replication and a checksum word. This
 word must be generated by us if you expect the game to accept modified data.

 Here is the sanity algorithm, ripped from the Dragon Warrior ROM in 6502
 assembly. I have added comments at the end of each line.

 $FBEF:A0 1D     LDY #$1D        ; load counter with 0x1D
 $FBF1:84 94     STY $0094       ; init checksum low byte
 $FBF3:84 95     STY $0095       ; init checksum high byte
 $FBF5:B1 22     LDA ($22),Y     ; load data[counter] into a
 $FBF7:85 3C     STA $003C       ; store to memory
 $FBF9:20 2A FC  JSR $FC2A       ; jump to subroutine
 $FBFC:88        DEY             ; y = y - 1
 $FBFD:10 F6     BPL $FBF5       ; repeat 0x1D + 1 times
 $FBFF:60        RTS             ; end of checksum algorithm

 $FC2A:98        TYA             ; put counter into a
 $FC2B:48        PHA             ; push counter to stack
 $FC2C:A0 08     LDY #$08        ; load new counter with 8
 $FC2E:A5 95     LDA $0095       ; load checksum high byte
 $FC30:45 3C     EOR $003C       ; xor data[counter] with checksum high byte
 $FC32:06 94     ASL $0094       ; shift left checksum low byte
 $FC34:26 95     ROL $0095       ; rotate shifted bit onto checksum high byte
 $FC36:06 3C     ASL $003C       ; shift left data[counter]
 $FC38:0A        ASL             ; shift left original checksum high byte
 $FC39:90 0C     BCC $FC47       ; skip if shifted bit was 0
 $FC3B:A5 94     LDA $0094       ; load checksum low byte
 $FC3D:49 21     EOR #$21        ; xor checksum low byte with 0x21
 $FC3F:85 94     STA $0094       ; store into checksum low byte
 $FC41:A5 95     LDA $0095       ; load checksum high byte
 $FC43:49 10     EOR #$10        ; xor checksum high with 0x10
 $FC45:85 95     STA $0095       ; store checksum high byte
 $FC47:88        DEY             ; y = y - 1
 $FC48:D0 E4     BNE $FC2E       ; repeat 8 times
 $FC4A:68        PLA             ; pull counter from stack
 $FC4B:A8        TAY             ; restore counter to y
 $FC4C:60        RTS             ; return

 It is a simple process, though fairly cumbersome for anyone to duplicate by
 hand. I would recommend either checksum bypass with a game genie or using
 dwsrame to fix the checksum for you. Here is the C++ conversion of the
 assembly routine used in dwsrame.

 wxUint16 SRAMFile::checksum(int game) const {
   wxASSERT((game >= 0) && (game < 3));

   unsigned char cl = 0x1D, ch = 0x1D, carry = 0;
   unsigned char al, bl, temp;

   for (int i = 0x1D; i >= 0; --i) {
       al = sram[GAME_OFFSET + (game * GAME_SIZE) + i];

       for (int j = 8; j > 0; --j) {
           bl = al ^ ch;

           // asl cl
           carry = (cl & 0x80) ? 1 : 0;
           cl <<= 1;

           // rol ch
           temp = (ch & 0x80) ? 1 : 0;
           ch = (ch << 1) | carry;
           carry = temp;

           // asl al
           carry = (al & 0x80) ? 1 : 0;
           al <<= 1;

           // asl bl
           carry = (bl & 0x80) ? 1 : 0;
           bl <<= 1;

           if (carry) {
               cl ^= 0x21;
               ch ^= 0x10;
           }
       }
   }

   return (cl | (ch << 8));
 }

 If you know basic arithmetic and binary operations, the algorithm should look
 pretty straightforwawrd. I will detail the operations real quick.

 We start with two counters. I will refer to these as checksum high and
 checksum low. They are unsigned bytes (range 0 - 255) and can be represented
 in 8 bits. Assign these two counters the initial value 0x1D.

 Starting at the end of the game data, which is at offset 0x1D from the start
 of a game slot, we do the following for each game byte from end to beginning.

 Grab the next byte of game data. I will refer to this as al.

 Do the following 8 times (once for each bit of the game data byte).

 Compute the exclusive OR of the game byte with checksum high. Shift the
 checksum low byte 1 bit left (this may result in a carry if the high bit was
 1 - do not discard this bit). Shift the checksum high byte left 1 bit. If a
 carry resulted from the checksum low shift, that bit should become the new
 low bit of checksum high. As with the first shift, do not discard the high
 bit shifted off of checksum high.

 Now shift left 1 bit the game data byte (al). If a carry results in this
 shift, it will replace any former carry.

 Now shift left 1 bit the exclusive OR we calculated earlier. If a carry
 results, it will replace any former carry.

 If we have a carry, then we XOR checksum low with 0x21 and XOR checksum
 high with 0x10.

 Repeat as directed.

 It's certainly an annoying process to do by hand, but not a complicated one.
 I would recommend you avoid doing this by hand though. The next section has
 a method for bypassing the checksum if you have a game genie or an emulator
 that supports game genie codes.

-------------------------------------------------------------------------------
| 4.4 Checksum Bypass Using a Game Genie
-------------------------------------------------------------------------------

 If you just want to poke around in the game data and change things without
 worrying too much about the checksum, one method you can use is a game genie.
 We can use a game genie code to bypass the sanity check.

 APVYNUAU will bypass the game sanity check and allow any modified SRAM data
 to work. What will happen if the data is invalid is unknown.

-------------------------------------------------------------------------------
| 5.0 dwsrame - The Dragon Warrior (NES) SRAM Editor
-------------------------------------------------------------------------------

 If you really want to edit the SRAM, I recommend a program called 'dwsrame',
 the Dragon Warrior (NES) SRAM Editor. Not surprisingly, I wrote it.

 It will edit any of the offsets I have outlined in this document an will
 keep fix the sanity values for you so you don't need to. It's far simpler
 than trying to edit by hand.

 If you want to try it out, head over to http://games.technoplaza.net/dwsrame/
 It's free software under the GNU GPL, tested in Windows, Linux, and Mac OS X,
 and is likely to run on almost any unix that support GTK+.

-------------------------------------------------------------------------------
| 6.0 Contact Information
-------------------------------------------------------------------------------

 The author (John Ratliff) can be contacted at
 webmaster [AT] technoplaza [DOT] net. Replace as necessary.

 I can also be reached via an online feedback form at
 http://www.technoplaza.net/feedback.php