Soul Doll Adapter Technical Documentation 0.4
December 18th, 2018
Shonumi aka D.S. Baxter


***************************************************
1. Introduction
*************************************************** 

The Soul Doll Adapter is a GBA accessory for the Legendz franchise, designed to allow data from plastic figurines to transfer over the games. The hardware came bundled with special editions of Legendz: Yomigaeru Shiren no Shima (released July 29th, 2004) and its sequel, Legendz: Sign of Necrom (released February 17th, 2005). The figurines, called "Soul Dollz" contain powerful monsters that players can use in battle. The Soul Dollz are "reborn" in the games, and from there they can level up and transfer that data back to the figurine.


***************************************************
2. General Hardware Information
***************************************************

- Soul Doll Adapter is a small pod that connects to the GBA via a short Link Cable
- The adapter also has a locking mechanism to keep the Soul Doll in place
- Presumably compatible with all Soul Dollz manufactured*
- Each Soul Doll is a small plastic figurine with a built-in IC at the bottom
- Each Soul Doll uses a 24LC08 serial EEPROM controller, stores 1KB of data

* Ones made after Yomigaeru Shiren no Shima was released may not be "recognized" in that game. If the data sent to the adapter is correct but the Soul Doll is not in the game's internal database, it is categorized as "unknown". 

 
***************************************************
3. Communication Protocol - Start Signal
***************************************************

The GBA and the Soul Doll Adapter communicate via the serial port using General Purpose Mode. The protocol is essentially bit-banging. For most of the protocol, the GBA sets both SC and SI high. To begin any communications with the Soul Doll Adapter, the GBA writes to following "device start signal" to RCNT:

Device Start Signal
--------------------
0x8020
0x8025
--------------------

The device start signal basically takes the Soul Doll Adapter out of standby-mode. The Soul Doll Adapter then accepts read or write commands to the EEPROM controller inside the Soul Dollz. When sending any commands or performing write operations, the start signal is always identified with Bit 7 of RCNT set to 0. When receiving data from commands through read operations, the start signal is always identified with Bit 7 of RCNT set to 1. For example, the least significant byte of RCNT may be the following for the start signals:

Start signal when issuing commands or performing writes:
--------------------
0x25 0x27 0x27 0x25
--------------------

Start signal when receiving data through read operations:
--------------------
0xA5 0xA7 0xA7 0xA5
--------------------

These signals determine when one command ends and another begins or when data is read or written.


***************************************************
4. Communication Protocol - Read Operations
***************************************************

The 24LC08 allows for random access at any given address. To do so, the EEPROM controller must receive the following 3 pieces of information:

1) Start Signal + Slave Address + Dummy Write Command
2) Start Signal + Word Address
3) Start Signal + Slave Address + Read Command

The slave address is 1 byte, with the Bits 4-7 being the device identifier (in the case of the 24LC08, this is 0b1010). Bits 1-3 are the device address. They effectively form the two MSBs of the final address (Bit 3 is ignored on the 24LC08, only use Bits 1-2). Bit 0 is the command; 0 = Write and 1 = Read.

The GBA uses 4 transfers per bits, with Bit 3 of RCNT determining whether the value is a "0" or a "1". A typical slave address sent via the GBA might look like this:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Bit 7               | Bit 6               | Bit 5               | Bit 4               | Bit 3               | Bit 2               | Bit 1               | Bit 0
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Device ID - 0b1010                                                                    | Ignored             | 2 MSB of final address                    | EEPROM command     
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5 | 0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5 | 0xA5 0xA7 0xA7 0xA5 | 0xAD 0xAF 0xAF 0xAD | 0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Data is received MSB first. The 1st and 4th transfers for each bit are probably irrelevant, however, the 2nd and 3rd transfers contain the actual data for the bit. So:

0xAD {0xAF 0xAF} 0xAD = Bit 3 is HIGH = 1
0xA5 {0xA7 0xA7} 0xA5 = Bit 3 is LOW = 0

The first slave address sent is basically ignored, as if the write command. This, however, prompts the 24LC08 to expect a word address next. The word address is the same format; 4 transfers per bit, with the 2nd and 3rd Bit 3 values determining whether it's a "0" or a "1". The word address forms the lower 8 bits of the final address to read from.

After the word address is sent, a final slave address is sent along with Bit 0 being set to 1 to indicate a read command. This final slave address forms the real two MSBs of the final address. Once this slave address and the read command are sent, EEPROM can be read from by sending a start signal followed by 32 transfers. The EEPROM controller doesn't seem to care what is sent during reading, so long as it's not another start signal. Once a full byte has been read, the internal pointer for the EEPROM address is incremented, and another read can be done simply by sending another start signal followed by 32 more transfers. The data format for reading looks something like this:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Bit 7               | Bit 6               | Bit 5               | Bit 4               | Bit 3               | Bit 2               | Bit 1               | Bit 0
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0x2D 0x2F 0x2F 0x2D | 0x25 0x27 0x27 0x25 | 0x2D 0x2F 0x2F 0x2D | 0x25 0x27 0x27 0x25 | 0x2D 0x2F 0x2F 0x2D | 0x25 0x27 0x27 0x25 | 0x2D 0x2F 0x2F 0x2D | 0x25 0x27 0x27 0x25
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Again, 2nd and 3rd transfers use Bit 3 to determine a "0" or a "1". The above example would be 0b10101010 or 0xAA. Once another command is detected, reading stops. One important thing to note, after sending the final slave address, the *very first* start signal still looks something like:

--------------------
0x25 0x27 0x27 0x25
--------------------

But *after* the 1st byte has been read, the start signal shifts to something like:

--------------------
0xA5 0xA7 0xA7 0xA5
--------------------

It isn't until another command is issued that the start signals swap. Generally, both Isle of Trial and Sign of Nekrom tend to read EEPROM in chunks of 128 bytes of 256 bytes. If the internal pointer for the EEPROM address is incremented past 0x3FF, it rolls over to 0x000. Apparently, when this happens, another device start signal must be issued.


***************************************************
5. Communication Protocol - Write Operations
***************************************************

Writing shares many of the same conventions as reading. The EEPROM controller needs 2 pieces of information:

1) Start Signal + Slave Address + Write Command
2) Start Signal + Word Address

It's exactly like reading, except no secondary slave address is issued, therefore what would normally be the dummy write command is actually acknowledged. Additionally, there is no need to shift to a different start signal; only [0x25 0x27 0x27 0x25] is used. Once the slave address, write command, and word address are sent, data is written using a start signal plus 32 transfers for the byte. Once again, the format of the byte looks something like this:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Bit 7               | Bit 6               | Bit 5               | Bit 4               | Bit 3               | Bit 2               | Bit 1               | Bit 0
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5 | 0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5 | 0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5 | 0xAD 0xAF 0xAF 0xAD | 0xA5 0xA7 0xA7 0xA5
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Again, 2nd and 3rd transfers use Bit 3 to determine a "0" or a "1". The above example would be 0b10101010 or 0xAA. Unlike reads, which can continue on updating the internal EEPROM address, writes are done in 16-byte pages. Up to 16-bytes can be written sequentially; anymore and the writes loop around. E.g. if writing to 0x100 a page write has a range of 0x100 to 0x10F. Attempting to write a 17th byte will overwrite 0x100 instead of 0x110. In order to write 0x110 to 0x11F, another write slave address, write command, and word address need to be sent to the 24LC08.


***************************************************
6. Soul Doll Data Format
***************************************************

Most of the 1KB data contained on the 24LC08 appears to be related to the Talispod or Talisdam accessories, e.g. such data as the Legend's preferred humidity and tempurature, and their stats. For the games, however, only bytes 0x300 - 0x3FF are relevant. This area of memory specifies the nickname, the owner's name, and various other flags related to auto-training mode and attached items. Most importantly, these bytes determine what kind of Legend is generated from the Soul Doll.

The layout of this memory varies depending on which Legendz game is being played. Data for Legendz: Yomigaeru Shiren no Shima and Legendz: Sign of Necrom change the location of the fields. While Sign of Necrom can recognize the format of Yomigaeru Shiren no Shima, data from Sign of Nekrom is incompatible with Yomigaeru Shiren no Shima.

For Yomigaeru Shiren no Shima, EEPROM data is arranged as follows:

-----------------------------------------------------------
Address		| Data Description
-----------------------------------------------------------
0x302		| Legend ID
0x351		| Training Bonus
0x398 - 0x39C	| Owner Name
0x3A1 - 0x3B0	| Message
0x3B1 - 0x3B9	| Legend Name
0x3D4		| Legend Level
0x3D5 - 0x3DE	| Legend Stats
0x3EE		| Auto Adventure Flag
0x3F0		| Attached Item Flag
0x3F1 - 0x3F2	| Attached Item Type & Quantity
0x3FE - 0x3FF	| Checksum
-----------------------------------------------------------

For Sign of Nekrom, EEPROM data is arranged as follows:

-----------------------------------------------------------
Address		| Data Description
-----------------------------------------------------------
0x302		| Legend ID
0x351		| Training Bonus
0x390 - 0x394	| Owner Name
0x3A1 - 0x3B0	| Message
0x399 - 0x3A0	| Legend Name
0x3BD		| Legend Level
0x3BE - 0x3C7	| Legend Stats
0x3CC		| Auto Adventure Flag
0x3CE - 0x3CF	| Attached Item Type & Quantity
0x3FC		| Attached Item Flag
0x3FE - 0x3FF	| Checksum
-----------------------------------------------------------

Byte 0x302 acts as the Legend ID. Depending on the value of this, the games will produce a different Legend. Their values are listed below:

0x01 = Windragon (A)?			0x21 = Command Windragon Break Armed		0x43 = Minotauros
0x03 = Windragon (B)?			0x22 = Command Blazedragon Volk Armed		0x44 = Oberon
0x04 = Mermaid				0x23 = Chimaera					0x45 = Lich
0x05 = Werewolf				0x24 = Triton					0x48 = Colonel Windragon Tornado Soul		
0x06 = Will 'o' Wisp			0x25 = Gargoyle					0x49 = Pheonix
0x07 = Tornado Kingdragon		0x26 = Cloud Giant				0x4A = Behemoth
0x08 = Blaze Dragon (A)?		0x27 = Command Windragon			0x4B = Jabberwock
0x09 = Goblin				0x28 = Command Blazedragon			0x4C = Leviathan
0x0A = Yeti				0x2B = Spiritual Windragon			0x4D = Fenrir
0x0B = Hell Hound			0x2C = Hexadragon				0x4E = Colonel Blazedragon Volcano Soul
0x0C = Volcano Kingdragon		0x2D = Windragon Berserker Mode (Growing)?	0x4F = Sphinx
0x0D = Windragon Berserker Mode		0x2E = Blazedradon Berserker Mode (Growing)?	0x50 = Cyclops
0x0E = Blazedragon Berserker Mode	0x31 = Devour Crocodile (Dandy)			0x54 = Syclla
0x0F = Fire Giant			0x32 = Harpy					0x55 = Titan
0x10 = Undine				0x33 = Cait Sith				0x56 = Echidna
0x11 = Peryton				0x34 = Command Blazedragon Volk Armed		0x59 = Ranshiin (B)?
0x12 = Troll				0x35 = Devour Crocodile				0x5A = Chibi Shiron (Manga Version)?
0x13 = Command Windragon		0x36 = Vampire					0x5B = Blazedragon (B)?
0x14 = Manticore			0x37 = Spiritual Kingdragon			0x5C = Windragon (Manga Version)
0x15 = Carbuncle			0x38 = Ogre					0x5D = Griffin
0x16 = Command Blazedragon		0x39 = Spriggan					0x5E = Bigfoot
0x17 = Dwarf				0x3A = Command Windragon Break Armed		0x5F = Tiamat
0x18 = Skeleton				0x3B = Bicorn					0x66 = Wyvern
0x19 = Earthquake Kingdragon		0x3C = Centaur					0x67 = Storm Kingdragon
0x1A = Storm Kingdragon			0x3D = Nekrom Kingdragon			0x68 = Carbuncle
0x1B = Wyvern				0x3E = Golem					0x6D = Giant Crab
0x1E = Ranshiin (A)?			0x3F = Ifrit					0x71 = Hydra
0x1F = Ranshiin (B)?			0x41 = Gorgon					0x72 = Iron Golem
0x20 = Chibi Shiron			0x42 = Kraken					0x73 = Valkyrie
											0x74 = Cerberus

Several IDs appear to be mapped to the same Legend. This may be explained by the fact that some Soul Dollz were released in A, B, and sometimes C variants. The plastic figurine is different, but the GBA games generate the same sprite and default name for the Soul Doll. All of the potential duplicates are marked with "?" in the list above. Although there are 103 Soul Dollz, the list remains incomplete. The gaps between entries do not generate valid Legendz, which suggests other bytes in EEPROM are also responsible for the ID.

1 byte represents the so called "Training Bonus" granted to a Legend when it is reborn. This adds a certain amount of points to its various base stats, such as HP, Strength, Defense, etc. The larger the value of this byte, the greater the stat boost will be. It has a limited range of valid values (1 = Minimum, 6 = Maximum).

2 bytes represent the quantity and type of attached items for a Soul Doll. A Legend can temporarily hold onto items from the player's inventory. Only 1 type of item can be given to a Legend at a time, but its quanitity can vary (1 = Minimum, 9 = Maximum).

5 bytes are used to store the owner's name. During the Soul Doll Initialization process, the player's name is registered to the Soul Doll. The games use this to lock the Soul Doll to a particular player. If the owner name written to EEPROM doesn't match the current one from the game's save file, EEPROM must be erased and the Soul Doll reset in order to use it. Each byte in EEPROM represents one character. The exact string format is currently unknown.

16 bytes are used to store a brief message inside the Soul Doll. This message can be checked during the Reborn process on a Soul Doll that was previously initialized for a given player. Each byte in EEPROM represents one character. The exact string format is unknown.

8 bytes are used to store the Legend's name. Each byte in EEPROM represents one character. The exact string format is currently unknown.

1 byte represents the level of the Legend. Its value ranges from 1 to 99.

10 bytes represent the various stats about the player's Legend inside the Soul Doll (HP, Strength, Defense, Magic Power, Magic Defense, and Speed). The size of each value varies in terms of bits, and the same value is usually spread over multiple bytes. See the next section for more information.

1 byte represents the Auto Adventure flag. When the Legend goes on an Auto Adventure, this byte is set to a non-zero value, otherwise it is set to 0x00. For Yomigaeru Shiren no Shima, this flag is always 0x01 when set. For Sign of Nekrom, it varies depending on the type of Auto Adventure, acting as a sort of ID.

Bytes 0x3FE through 0x3FF are a 16-bit checksum the data 0x380 through 0x3FD. The checksum is computed by adding up every byte within that range. If the checksum is incorrect, both Legendz games will treat the entire Soul Doll data as invalid, which will require it to be reinitialized. After calculating the initial checksum, it must be XOR'ed with a separate 16-bit value. Yomigaeru Shiren no Shima uses 0x4832, while Sign of Nekrom uses 0x4C32. Sign of Nekrom can detect both types of checksums and uses this to determine which game last modified EEPROM data.


***************************************************
7. Soul Doll Data Stats
***************************************************

Use the following psuedocode to obtain the values for each attribute of the Soul Doll's Legend. Assume that ADDRESS is the specified the EEPROM address 0x3D5 (for Yomigaeru Shiren no Shima) or 0x3BE (for Sign of Nekrom).

-----------------------------------------------------------
HP
-----------------------------------------------------------
VAL1 = READ 16 BITS FROM (ADDRESS)
VAL2 = READ 08 BITS FROM (ADDRESS + 2)
HP = (VAL_1 >> 6) | ((VAL & 0x0F) << 10)


-----------------------------------------------------------
STRENGTH
-----------------------------------------------------------
VAL1 = READ 16 BITS FROM (ADDRESS + 2)
STRENGTH = ((VAL1 << 18) >> 22)


-----------------------------------------------------------
DEFENSE
-----------------------------------------------------------
VAL1 = READ 16 BITS FROM (ADDRESS + 6)
DEFENSE = ((VAL1 << 20) >> 22)


-----------------------------------------------------------
MAGIC POWER
-----------------------------------------------------------
VAL1 = READ 32 BITS FROM (ADDRESS + 2)
MAGIC POWER = ((VAL1 << 8) >> 22)


-----------------------------------------------------------
MAGIC DEFENSE
-----------------------------------------------------------
VAL1 = READ 32 BITS FROM (ADDRESS + 6)
MAGIC DEFENSE = ((VAL1 << 10) >> 22)


-----------------------------------------------------------
SPEED
-----------------------------------------------------------
VAL1 = READ 08 BITS FROM (ADDRESS + 6)
VAL2 = READ 08 BITS FROM (ADDRESS + 5)
SPEED = ((VAL1 & 0x03) << 8) | VAL2


***************************************************
8. Soul Doll Data Obfuscation
***************************************************

The EEPROM data is obfuscated with a repeating 32-bit key. This makes the data somewhat inaccessible unless parsed first. The 32-bit key is 0xA8262CDB as an LSB first value. Each 32-bit value from EEPROM is simply XOR'ed by the key. Another way to unscramble EEPROM is demonstrated by the following psuedocode:

ARRAY = 0xDB, 0x2C, 0x26, 0xA8
UNSCRAMBLED VALUE = EEPROM BYTE XOR ARRAY[EEPROM ADDRESS AND 0x03]

This obfuscation only occurs on bytes 0x380 through 0x3FF. The checksum is calculated and XOR'ed by its own 16-bit value before XOR'ing this 128-byte region with the above mentioned 32-bit value.
