PlayStation 2: Serial Input Output 2, Memory Cards, Controllers, Multitaps, and More!

This document outlines the Serial Input Output 2 bus and the memory cards, controllers, multitaps, and anything else developers tried to cram into those ports.

This document is a work in progress. Updates will continue to roll in as I have time to work on it.


Words, Terms, Slang, Lingo

Throughout this document there will be a number of words, terms, slang, lingo, whatever you want to call it. Here's my attempt at defining some of these.

Word Meaning
SIO2 "Serial Input Output 2"
memcard "memory card"
fs "filesystem", "file system", "file-system"
ECC "Error Correction Code"
FAT "File Allocation Table"
pad "controller", "game pad", "joy pad"

Serial Input Output 2 (SIO2)

SIO2 Register Memory Map

Name Address Data Type Description
SEND3 0x1F808200 - 0x1F80823F int[16] Used internally by SIO2MAN to track how many commands it is sending, to which physical ports, and how long they are.
SEND1/SEND2 0x1F808240 - 0x1F80825F int[8] Unknown. Collectively this register is an int[8] type but how specifically it works is a bit of a tangled mess. If bit 2 is cleared, SIO2MAN treats it as SEND1, if bit 2 is set, SIO2MAN treats it as SEND2.
FIFO_IN 0x1F808260 char Hardware address wired to the command rail of the front ports; SIO2MAN writes commands to this register.
FIFO_OUT 0x1F808264 char Hardware address wired to the data rail of the front ports; peripherals send their response data and SIO2MAN reads it from here.
CTRL 0x1F808268 int Control register for SIO2. Known bits include 0 for starting command transfers, and 2 and 3 which reset SIO2. Most variants of SIO2MAN seem to set this register to 0x000003BC on resets.
RECV1 0x1F80826C int Written by unknown means, this register is updated to reflect the status of peripherals addressed by a packet. This register is never written to from IOP space. IOP modules read this register, typically after FIFO_IN writes are finished, and before FIFO_OUT reads begin.
RECV2 0x1F808270 int Written by unknown means, purpose unknown. IOP modules read this register, typically after FIFO_IN writes are finished, and before FIFO_OUT reads begin.
RECV3 0x1F808274 int Written by unknown means, the upper short seems to be the size of the data received. IOP modules read this register, typically after FIFO_IN writes are finished, and before FIFO_OUT reads begin.

SIO2 Registers

SEND3

This register is an array of 16 ints. For each int:

Bit Name Description
0 Port Which physical port on the front of the console is being targeted. When unset, this maps to "1" on the front of the console, when set this maps to "2" on the front of the console.
1-7 Unused No known purpose.
8-17 Fake Length

Specifies a "fake" length of the command in bytes. Some games will still report the full length of the command here, others will report only a part of the command's proper length here.

It is not absolute, but it seems like a general rule here is that, of games which do not report the real length here, they tend to specify a "length that actually matters", in other words of the bytes in the command, which ones actually are conveying information rather than just padding out the length (e.g. an attempt to set a sector, normally a 9 byte command, may be shortened to 7 here). Or, in the case of a read or write command, a game may only specify the length of the header/footer bytes, with the actual data being read or written subtracted from the length (e.g. a read command for 128 bytes of data, normally a total command length of 134, may have a length of 6 here, and if we combine that with the previous rule to trim useless bytes, we might even end up with 3 here for a read).

18-27 Actual Length Specifies the actual length of the command in bytes. This will always contain the full length of the command, in bytes.
28-31 Unused No known purpose.

SEND1/SEND2

FIFO_IN

Register where IOP modules can write commands to be sent to peripherals. Unlike SIO0 which specifically would transfer and receive one byte at a time, SIO2 transfers and receives in bulk. All command bytes are written sequentially, then all data bytes are read sequentially.

It is unclear what the underlying electrical mechanism is for this, but unlike SIO0 it is not driven by IRQs, nor do the CTRL and ISTAT registers play a role. This seems to work autonomously at the electrical level by unknown means. It is highly likely that this would mirror the behavior of how the rails worked on the PS1, as the PS2 IOP modules know how to talk to PS1 memory cards.

This register only 32 bits wide and only ever written to with a single byte.

FIFO_OUT

CTRL

RECV1

Classically believed to tell us strictly if any one device is plugged in. But after provoking a PS2 with some homebrew, blasting it with various pad commands, plugging and unplugging controllers all the while, some more nuanced behavior can be observed. While this list is not exhaustive of every possible open/disconnect pairing, I do believe it encapsulates all of the possible outcomes.

RECV1 Test Results (Pads Only)

These scenarios may need some additional runs - these were carried out with the PS2SDK pad module and its behavior seems flaky at best. I encountered multiple scenarios where polls were returning inputs from the wrong pad, or the printf statements in my code simply would not run, and there would be no indication of where or why the code just stopped running.

Scenario RECV1 Comments
  • No controllers plugged in at boot.
0x001EB7C8
  • Pad 1 is plugged in at boot.
  • Pad 1 is opened.
0x00001100
  • Pad 1 is plugged in at boot.
  • Pad 1 is opened.
  • Pad 1 is disconnected.
0x0001D100
  • Pad 1 is plugged in at boot.
  • Pad 2 is opened.
0x001EB7C8 Inconsistent. Initial test yielded the above, further attempts yielded 0x00001100, but the test ELF (continuing to inspect the SIO2 transfer) would TLB miss shortly after. Retail games will always try to initialize pad 1 alone, or both pads together, so I consider this test result fun but meaningless.
  • Pad 2 is plugged in at boot.
  • Pad 2 is opened.
0x00001100 Impractical to try to use port 2 without port 1, but technically nothing wrong with it.
  • Pad 2 is plugged in at boot.
  • Pad 2 is opened.
  • Pad 2 is disconnected.
0x0001D100
  • Pad 2 is plugged in at boot.
  • Pad 1 is opened.
0x001EB7C8 Curiously, this run does not seem to TLB miss my PS2, unlike the test where I plugged in Pad 1 and opened Pad 2. A key difference is my test ELF freezes in place on this scenario, as opposed to the other which continued to try and check the pad.
  • Pad 1 and Pad 2 are plugged in at boot.
  • Pad 1 is opened.
0x00001100
  • Pad 1 and Pad 2 are plugged in at boot.
  • Pad 1 is opened.
  • Pad 1 is disconnected.
0x0001D100
  • Pad 1 and Pad 2 are plugged in at boot.
  • Pad 1 and Pad 2 are opened.
0x00001200
  • Pad 1 and Pad 2 are plugged in at boot.
  • Pad 1 and Pad 2 are opened.
  • Pad 1 is disconnected.
0x0001D200
  • Pad 1 and Pad 2 are plugged in at boot.
  • Pad 1 and Pad 2 are opened.
  • Pad 2 is disconnected.
0x0002D200
  • Pad 1 and Pad 2 are plugged in at boot.
  • Pad 1 and Pad 2 are opened.
  • Pad 1 and Pad 2 are disconnected.
0x0003D200
Multitap Differences

RECV1 behaves a bit differently with multitaps. Normally for pads, bits 16 and 17 being set would indicate if port 0 and port 1 were empty, respectively. Instead, if either multitap is missing (or both), only bit 16 is set, regardless of port. MTAPMAN only evaluates bit 16, not 17, when trying to determine if the device is not present.

RECV2

RECV3


PlayStation 2 Memory Cards

Memcard Filesystem

Data Structures

The PS2 memcard filesystem can be broken down into a few different data structures or organizational units.

Page

A group of data bytes, followed by ECC bytes. The data bytes can be either 512 or 1024 bytes long; this is the Page Length attribute specified in the superblock. OEM memcards from Sony will always use 512 bytes. Though the 1024 byte size is supported, there are no known cases (yet) of a real memcard actually using this.

The ECC bytes following the data bytes are 16 bytes long if the page length is 512, or 32 bytes long if the page length is 1024. In either case, every 128 bytes of data corresponds to 3 bytes of ECC data.

Physical Size Data Bytes Used Data Bytes Total ECC Bytes Used ECC Bytes Total Data Byte to ECC Byte Mapping
528 512 512 12 16 128 bytes data = 3 bytes ECC
1056 1024 1024 24 32 128 bytes data = 3 bytes ECC
Cluster

A group of pages. Clusters can be 1 or 2 pages long; this is the Pages Per Cluster attribute specified in the superblock. OEM memcards from Sony will always use Pages Per Cluster = 2. If the Page Length attribute of the superblock is 1024, then Pages Per Cluster must be 1.

Page Length Pages Per Cluster = 1 Pages Per Cluster = 2
512 Supported Supported
1024 Supported NOT Supported

Clusters are primarily used in the FAT and for navigation. Presumably, it requires a smaller FAT this way (at least for OEM memcards where 1 cluster = 2 pages = 1024 data bytes); a single FAT entry points to two pages worth of data, rather than having a FAT entry for every page. The disadvantage is that small, loose files can lead to wasted space. A single FAT entry points to one cluster, so whatever file belongs to that FAT entry ends up consuming both pages even if it is only 256 bytes long, leading to 768 unused data bytes.

Directories do remedy this partially by leveraging each individual page as a directory entry. When populating a directory tree for a memory card, the FAT is traversed and this tells you what clusters and in what order to traverse them to populate the directory tree. When a cluster is visited, it is simply expected that each page can be an individual directory entry, and so both pages at that cluster position are checked individually.

Contrast with files, a single file is given a single cluster position, and there is no indication or expectation that two files can live on different pages in the same cluster, so any unused space across the entire cluster is lost until the file is deleted and the cluster's pages can be reallocated to a new file or directory entry.

Erase Block

A group of pages. Erase blocks default to 16 pages long; this is the Pages Per Erase Block attribute specified in the superblock. 16 is the maximum number of pages supported per erase block. It is unclear whether this number can be reduced.

Erase blocks are the units of which a memcard can be erased. Because memcards are flash memory, bits can only be flipped one direction. In all known cases, the "default" position of a bit is 1, and bits can only be flipped to 0. To flip back to 1, an entire erase block must be "cleared" to 1's. As such, prior to any write operation, a page's entire erase block must be erased first.

Superblock

The superblock is the "brain" of the memcard. This page stores information describing the size and health of the memcard.

Quotes found in the below table are to express that something is a string value. The values themselves do not contain quote characters.

Offset Name Data Type Default Description
0x00 Format String char[28] "Sony PS2 Memory Card Format " Constant ASCII string. Evaluated when checking if a memcard is formatted. Will be present on a formatted memcard, missing otherwise. This string ends with a space, and is not null terminated!
0x1C Version char[12] "1.x.0.0" Version string. Version "1.2.x.y" has full support for the Bad Block List, older versions have limited or none. This string is null terminated (unused bytes are null terminators). It's currently unclear if this version number is provisioned by the console or the card.
0x28 Page Length short 512 Size in bytes of a memcard page. Can be either 512 or 1024. No known cases of a real memcard using 1024.
0x2A Pages Per Cluster short 2 Number of pages in a memcard cluster. Can be 1 or 2 if page length is 512, must be 1 if page length is 1024.
0x2C Pages Per Block short 16 Number of pages in a memcard erase block.
0x2E Unknown short 0xff00 Doesn't appear to be used, purpose unknown.
0x30 Clusters On Card int 8192 Size of the memcard in clusters.
0x34 Allocation Offset int 0x41 Offset of the first "allocatable" cluster. Offset is relative to the beginning of the memcard. Cluster values in the FAT and directory entries are then relative to this cluster. "Allocatable" means a cluster which is not reserved for a special purpose (e.g. FAT or backup) and can be used to store files and make directory entries.
0x38 Allocation End int
0x3C Root Directory Cluster int
0x40 Backup Block 1 int
0x44 Backup Block 2 int
0x48 Unknown int
0x4C Unknown int
0x50 Indirect FAT Cluster List int[32]
0xD0 Bad Block List int[32]
0x150 Card Type char
0x151 Card Flags char
0x152 Unknown short
0x154 ClUster Size int
0x158 FAT Entries Per Cluster int
0x15C Clusters Per Block int
0x160 Card Form int
0x164 Root Directory Cluster 2 int
0x168 Unknown int
0x16C Unknown int
0x170 Max Allocatable Clusters int

File Allocation Table (FAT)

Directory Tree

Formatting

Memcard Commands

Memcards accept a number of commands, encoded as streams of bytes sent over the SIO2 bus.

0x11 - Probe

A basic heartbeat command to test if a memcard is present in a port. Only the last two response bytes matter, they should be 0x2B and the memcard's current terminator byte.

Byte (zero indexed) 0 1 2 3
Command 0x81 0x11 0x00 0x00
Response 0x00 0x00 0x2B Terminator

0x12 - Unknown (Write/Delete End)

A command which games send to memcards after writes or erases. Its purpose is currently unknown. A theory is that this is some kind of acknowledge signal; sceMcSync is used on the EE to check if a memcard function has completed or stall until it does. Perhaps sceMcSync is waiting for this command to be processed?

This command conventionally has a length of 4 bytes. Only the last two response bytes matter, they should be 0x2B and the memcard's current terminator byte. The 3rd byte seems to switch between 0x00 and 0x3F, but this appears to be arbitrary to the command completing. Additionally a value may appear at command byte 6, beyond the length specified in the SEND3 register when this command is used, but this too appears arbitrary to completion.

Byte (zero indexed) 0 1 2 3
Command 0x81 0x12 0x00 0x00 or 0x3F
Response 0x00 0x00 0x2B Terminator

0x21 - Set Page (Erase)

0x22 - Set Page (Write)

0x23 - Set Page (Read)

0x26 - Get Specs

0x27 - Set Terminator

0x28 - Get Terminator

0x42 - Write Data

0x43 - Read Data

0x52 - PS1 Read

0x53 - PS1 State

0x57 - PS1 Write

0x58 - PS1 Pocketstation Probe

0x81 - Read/Write End

0x82 - Erase Block

0xBF - Unknown Boot

0xF0 - Authentication (Multiple XOR)

0xF3 - Authentication (F3)

0xF7 - Authentication (F7)

Games With Defective/Dangerous Memcard Code

A number of games have been found over the years to contain behavior which is dangerous to memcards.

Jak X Combat Racing

Jak X Combat Racing has a bug where the game will soft lock while saving. After waiting a decent amount of time, it does seem like it becomes safe to reset the PS2, and that save data is actually being fully committed to the memcard. However, according to user reports this does not always seem to be the case, so it is best to try and work around this bug whenever possible. This bug affects all regions (NTSC/PAL alike) and occurs on all PS2 models. There may be a higher likelihood to encounter this issue on a slim PS2, however it is not exclusive to slims nor can this be conclusively verified.

The bug is best worked around by ejecting the memory card prior to any save operations. Let the game detect that the card is missing, then reinsert it and let the game save. Be sure not to ever eject a memory card during a save or load operation.

Naughty Dog allegedly patched this issue in the Greated Hits release of the game. For PAL regions, this would be the "Platinum" version, if one exists.

Soul Calibur 3

Soul Calibur 3 has an issue where any data written to a memcard prior to its own save file being placed on the card must not be modified. Any kind of change to the size of a file written to the card before Soul Calibur 3's save file was added, will result in Soul Calibur 3 no longer recognizing its own save file and instead saying it is corrupt. This issue is known to affect all versions (NTSC/PAL alike).

This issue is best worked around by plain and simply giving this game its own memory card.

It is highly likely the developers chose to do some kind of nonstandard practice revolving around the FAT on the memcard. However, it is not exactly clear what this would entail; the most likely explanation is that they are doing something bizarre to the FAT. That raises additional questions however, as the FAT is only accessible from the IOP module, suggesting modifications may have been made to MCMAN. The standard memory card functions are invoked from the EE and behave extremely similarly to stdio, using file descriptors and paths rather than page manipulation.

PlayStation Underground Holiday 2004 Demo Disc

The PlayStation Underground Holiday 2004 Demo Disc ended up being a nightmare for many gamers alike and a liability for all who took part in its release. It was directly responsible for many save files being irreversibly destroyed.

While simply booting the demo disc is fine, as are most games on the disc, the disc contains a demo for Viewtiful Joe 2. This demo has code in it which issues multiple memory card format commands, as well as multiple memory card write commands. The formats will wipe out the FAT and return the card to a "fresh" state. The write commands will then overwrite seemingly random areas of the card with garbage. It is worth noting most of the writes end up being out of bounds, and/or misaligned. All data on the memcard is lost at this point.

Running the format function on a memory card is a very deliberate action for a game to take. As is writing data to a memory card. To suggest that this is truly a bug, and not malicious action taken by a rogue developer seems to be a gross mischaracterization of the amount of deliberance and effort taken to ensure this release made it on to this demo disc. Even during development, having the boot sequence of your game run the memory card format function multiple times is not something you would do. Having the boot sequence of your game run memory card writes to random, misaligned addresses, is not something you would do. Having your game run memory card writes targeted to addresses in the first place, is not something you can do from the SDK. You need to modify an IOP module to make that happen.

Either they had a really, really, REALLY bad time with some unfortunate undefined behavior that no one noticed before this demo made it out the door. Or, someone made sure that this demo had a little bit of a different startup sequence in it, and managed to make sure no one found out about it until the first poor sap ran this demo.


PlayStation 2 Controllers

Digital Button Mapping

All controllers will use two bytes in positions 3 and 4 (zero indexed) of their poll commands to store all of the digital button states. The table below shows which bits correspond to which buttons.

Byte 3:

Bit 7 (MSB) Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 (LSB)
Left Down Right Up Start R3 L3 Select

Byte 4:

Bit 7 (MSB) Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 (LSB)
Square Cross Circle Triangle R1 L1 R2 L2

Pad Identification/Handshake Commands and Responses

Most pads, with the exception of the PS1 digital pad, can be issued configuration commands by the PS2 to change their operating mode and identify their capabilities to the PS2.

While there are some specific commands which are situational and will have specific details explained, many of these commands are static, predictable responses simply aimed to tell the PS2 what type of pad it is or how many of some thing the pad has.

PS1 Digital Pad

The most basic pad to ever grace the Playstation ecosystem. 14 face buttons, all digital on/off values with no analog sticks or pressure capability.

This controller does not support any configuration commands, including the command to enter/exit config mode itself.

Poll

Get all inputs on the controller. Plain and simple. Bytes 3 and 4 are the digital mappings.

Byte (Zero Indexed) 0 1 2 3 4
Command 0x01 0x42 0x00 0x00 0x00
Data 0xFF 0x41 0x5A 0xFF 0xFF
Config

Ask the controller to enter or exit config mode. Digital pads may receive this command from the PS2 as it first doesn't know if the pad is truly digital only. The pad will respond that it has no idea what the command is, and that tells the PS2 it is a digital pad.

Interesting note - the RECV1 value on this command with only one digital pad inserted in particular is 0x0001D100, as opposed to 0x00001100 as expected for a normal poll.

Byte (Zero Indexed) 0 1 2 3 4
Command 0x01 0x43 0x00 0x01 0x00
Data 0xFF 0x41 0xFF 0xFF 0xFF

DualShock 2 Vibration Motors

Motor Setup

The DualShock 2 has two vibration motors, small and large. They are controlled by the 3rd and 4th (zero indexed) command bytes of a pad poll. Take the following pad poll command for a digital pad (analog and pressure values simply don't matter here):

Byte (Zero Indexed) 0 1 2 3 4
Command 0x01 0x42 0x00 0x01 0xff
Data 0xFF 0x41 0x5A 0xFF 0xFF

Under normal circumstances, the small motor is controlled by the 3rd byte, and large motor by the 4th. This particular example would turn on the small motor with power level 0x01, and turn on the large motor with power level 0xff. However, the pad protocol supports remapping these.

The vibration config command's 3rd and 4th (zero indexed) bytes correspond to small and large motor. Whichever values are supplied in these positions of the console's command then determines which byte of a pad poll that motor will get its power level from.

The normal thing to do would be for the 3rd byte to be 0x00, and the 4th byte to be 0x01. In other words, the small motor will look at the first vibration value (the 3rd byte of the poll), and the large motor will look at the second vibration value (the 4th byte of the poll).

It is uncommon, but some games such as FFX do rearrange the motors. Take the example of a vibration config command where the 3rd byte is 0x01, and the 4th byte is 0x00; this would set small motor to the second vibration value (the 4th byte of the poll), and large motor to the first vibration value (the 3rd byte of the poll). In such a case, if you then wanted to turn on both motors to full power, your pad poll would now look like:

Byte (Zero Indexed) 0 1 2 3 4
Command 0x01 0x42 0x00 0xff 0x01
Data 0xFF 0x41 0x5A 0xFF 0xFF

Motor Power

Power delivery to the motors is handled directly in software. Both the small motor and large motor are set using an unsigned char value.

The small motor is binary and only considers the LSB of the unsigned char. In other words, if it is an odd number, the small motor will turn on. If an even number, it will turn off.

The large motor considers the full range of the unsigned char and will power on accordingly. However, due to either a hardware cutoff, the motor's physical weight being to high, or some combination of both, the motor will only start actually spinning at a certain power level.

On my DS2, the first perceivable large motor vibration was felt at 0x40, but it was barely able to work, and simply shaking the controller a little was enough for the weight of the motor to overcome the power delivered to it.


PlayStation 2 Multitaps

The multitap is a peripheral which plugs in to both a memory card and pad port at the same time. It expands each of these ports into four slots. Two multitaps can be plugged in for a total of eight slots.

Internally, each of the two ports gets four slots assigned to it and these map predictably to the letters shown on the multitap. Slot A = 0, Slot B = 1, Slot C = 2, Slot D = 3.

Pad and memcard functions almost always take port and slot parameters. The port refers to the two physical port on the front of the PS2, and slot refers to the four multitap slots. If the software has no intent to use the multitaps, the slot is always 0.

Multitaps are effectively switches or routing devices. It is assumed that, after being plugged in, if they do not receive any commands to change the routing target, they default to just forward all commands to slot A.

FreeMCBoot Compatibility

FreeMCBoot memcards can only be successfully used in multitap slot A. Inserting a FreeMCBoot memcard into any other slot will have no effect and the system will boot normally.

Games With Bizarre Multitap Behavior

There are some general conventions that, while not enforced or really even recommended, were just generally "the thing to do". With multitaps, one of those is making a sort of abstraction layer where the game can reasonably work out which controller should map to which player in the game. Even here there's probably plenty of different ways developers could and would implement this in their games. But some games took a bit of an unusual approach.

Digimon Rumble Arena 2

Digimon Rumble Arena 2 chose to simplify its controller handling by requiring you to use your multitap in port 2. The game will always expect to find a pad in port 1 with no multitap. Perhaps they thought "people will always want a pad in their first port, it's the second one which may or may not be used; so lets only check for multitaps there". Or, they got lazy and only wanted to run multitap checks against port 2. The latter seems a little more likely - rather than run some kind of abstraction layer where "the Xth pad to connect takes the Xth player slot in-game", the multitap slots are literally hard coded to the player slots in-game.

If you have a multitap in port 1, slot A continues to work in the multitap's "default" state, none of the other slots work. Port 2 still works normally.

If you have a multitap in port 2, port 1 = player 1, slot 2-A = player 2, slot 2-B = player 3, slot 2-C = player 4, slot 2-D is not useable. That's right. 2-A, 2-B, 2-C get hard coded to the in-game players, and you are not allowed to scramble that at all.

What's worse, the manual tells you to put your multitap into port 1! The one that doesn't work!

Downhill Domination

Downhill Domination is incredibly literal minded with its multitap implementation. The game only accepts a multitap in port 1. Attempting to use a multitap in port 2 results in the same "default behavior" as any other game - slot 2-A is treated the same as literal port 2, the rest of the slots are dead.

When a multitap is inserted to port 1, the game no longer considers port 2 valid. All controllers must be connected through the multitap. For the game to detect X controllers, the controllers must all be connected sequentially. Any empty slot in the multitap results in the game thinking that slot plus any others after it are empty.

Even if you are trying to play two player, the multitap gets in the way! Using slot 1-A and port 2 together, the game will not detect the second controller.

WWE SmackDown! Here Comes the Pain

WWE SmackDown! Here Comes the Pain requires multitap slots to be filled sequentially. Port 1 must be multitapped first. If port 2 is multitapped without multitapping port 1, slot 2-A is treated the same as literal port 2, the rest of the slots are dead.

With a port 1 multitap, port 2 is ignored until all slots on the multitap are occupied, at which point it becomes available for player 5. For the game to detect X controllers, the controllers must all be connected sequentially. Any empty slot in the multitap results in the game thinking that slot plus any others after it are empty.

With both ports multitapped, slots must still be occupied sequentially; port 1's multitap filled first, then the rest in the port 2 multitap.


Sources

Ross Ridge's "PlayStation 2 Memory Card File System" Document

Provides information on the entire PS2 memcard filesystem.

Links

PSI's "ps2tek" Document

Absolutely critical in making heads or tails of the PS2's IOP modules for SIO2, memcards, and pads.

Links

Campaign4Games' File Corruption Document for Soul Calibur III on GameFAQs

Provides a full user-level breakdown of Soul Calibur III's issues with save files.

Links