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.
Another important detail to note is later in the PS2's lifecycle, Sony introduced libmc2 and libpad2 which, in my opinion, complicate things substantially more. The IOP modules used in tandem with these EE libraries are much more tightly integrated with DBCMAN. This decision makes sense for device management purposes; this way all the various I/O devices, controlled by SIO2 or not, can be handled as devices out of a single module.
However, for the sake of reverse engineering, I find it substantially harder to work with. Most information revolves around the original libmc, libpad, and the IOP modules they talk to. Information about the updated EE libraries and IOP modules will be sparse, if not missing from this document, for the foreseeable future.
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" |
Name | Address | Data Type |
---|---|---|
SEND3 | 0x1F808200 - 0x1F80823F | int[16] |
SEND1/SEND2 | 0x1F808240 - 0x1F80825F | int[8] |
FIFO_IN | 0x1F808260 | char |
FIFO_OUT | 0x1F808264 | char |
CTRL | 0x1F808268 | int |
RECV1 | 0x1F80826C | int |
RECV2 | 0x1F808270 | int |
RECV3 | 0x1F808274 | int |
Used internally by SIO2MAN to track how many commands it is sending, to which physical ports, and how long they are.
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. |
A mystery pair of registers whose exact purpose is unknown. Though these registers both exist interweaved in the same memory address, IOP modules reference these both as separate registers. Bit 2 (zero indexed) can be used to tell if it is SEND1 (unset) or SEND2 (set).
Register where IOP modules can write commands to be sent to peripherals. Though named as FIFO, this is not a queue but a single register to place one byte of data at a time. This register is 32 bits wide, but only the LSB is ever written.
It is unclear what the underlying electrical mechanism is for this, but possible that the ISTAT or CTRL register play some role in controlling when the data written here is transmitted to a peripheral.
Register where IOP modules can read data received from peripherals. Though named as FIFO, this is not a queue but a single register to place one byte of data at a time. This register is 32 bits wide, but only the LSB is ever read.
It is unclear what the underlying electrical mechanism is for this, but it is possible that the ISTAT or CTRL register play some role in controlling when the IOP module is notified of the data put here by a peripheral.
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.
Written by unknown means, this register is updated to reflect the status of the peripheral being communicated with. 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.
The following general rules seem to explain well enough the meanings of the values found in RECV1:
1
= no opened device is missingD
= at least one device which was previously opened is now missing1
= port 1 opened but missing2
= port 2 opened but missing3
= ports 1 and 2 opened but missingThese 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 |
---|---|---|
|
0x001EB7C8 |
|
|
0x00001100 |
|
|
0x0001D100 |
|
|
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.
|
|
0x00001100 |
Impractical to try to use port 2 without port 1, but technically nothing wrong with it. |
|
0x0001D100 |
|
|
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. |
|
0x00001100 |
|
|
0x0001D100 |
|
|
0x00001200 |
|
|
0x0001D200 |
|
|
0x0002D200 |
|
|
0x0003D200 |
Memory card behavior seems to vary slightly, at the very least due to a change in testing methodology. While most of the core principles from the pad tests still apply, a new behavior focusing around ejection can be observed.
In all cases, MCMAN does a bitwise AND against RECV1 and a mask of 0xF000, then checks if the result is 0x1000. If it passes this, then its considered healthy. If not, then it considers it a failure.
It isn't clear why without further investigation into the IOP module but it does seem there is a correlation between RECV1 being set to 0x00001700, and a memory card needing to have sceMcGetInfo
ran against it a second time. Proper use of this function is that if it returns a negative value, the card was newly inserted. This is intended to serve as a sort of warning to signal to the game
code on the EE that the card has been sort of "re-initialized", and should be checked one more time. While it is possible and would make sense that the extra, unused bits on the third nibble could be leveraged
to signal "newly inserted", it is not confirmed that RECV1 value having these extra bits set is what triggers the negative return value from sceMcGetInfo
.
Each test case below is incremental and adds an additional step to the last case.
Scenario | RECV1 | Comments |
---|---|---|
|
0x00001700 |
This matches a success pattern that would be expected from a pad, but interestingly has additional bits set on the third nibble. They seem to be of no consequence, but their purpose is not clear. |
|
0x00001100 |
The expected RECV1 value for a present memcard now occurs. |
|
0x0001D100 |
The expected RECV1 value for a missing memcard now occurs. |
|
0x00001700 |
Returns to the success pattern with extra bits set. |
|
0x00001100 |
Returns to the expected RECV1 value for a present memcard. |
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.
Written by unknown means, purpose unknown. IOP modules read this register, typically after FIFO_IN writes are finished, and before FIFO_OUT reads begin.
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.
Some registers have some special considerations that can be made in the context of emulation.
For the purposes of emulation, a lot of the timing constraints found on SIO0's equivalent registers do not apply to FIFO_IN and FIFO_OUT in SIO2; the PS1 depended on tight timing due to SIO0 being tightly woven into the kernel. However, these registers can be reliably emulated without such considerations because the IOP modules do almost all state management in high level software.
The primary mechanism by which commands flow in to SIO2 and data flows out are writes to FIFO_IN, and reads from FIFO_OUT. These memory writes and reads are all issued by IOP modules. There is no special mechanism which needs emulated in order to support this behavior, besides having a place to store values for these registers.
When the IOP writes to FIFO_IN, an implementation can instantly transmit that to the emulated peripheral, take the emulated peripheral's data byte, and store that to FIFO_OUT. There is no need to wait for other register statuses; the IOP module which issued the write to FIFO_IN will subsequently issue a read on FIFO_OUT.
The PS2 memcard filesystem can be broken down into a few different data structures or organizational units.
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 |
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.
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.
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 |
Memcards accept a number of commands, encoded as streams of bytes sent over the SIO2 bus.
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 |
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 |
One of the new features introduced to PS2 memory cards is copy protection. Quite simply, a save file can be flagged as protected, and if so, the BIOS will refuse to copy it to another memory card. The implementation of the copy protection is done entirely in the PS2 BIOS; other software can simply choose not to implement it, and completely bypass it. LLE emulators are an exception to this, as they will continue to execute the native BIOS code which includes copy protection.
Title | Serials/Regions Known |
---|---|
PS2 Network Configuration (BWNETCONF) | NTSC-J |
Monster Hunter | SLUS-20896, SLES-52707, SLPM-65495 |
Monster Hunter 2 dos | SLPM-66280 |
Sims 2 Castaway | SLES-54903 |
Sims 2 Pets | SLES-54347 |
Star Ocean: Till the End of Time (Battle Trophies) | SLUS-20488, SLUS-20891 |
Timesplitters (Game Settings) | SLES-50078 |
Timesplitters 2 (Game Settings) | SLES-50877 |
Some games are incompatible with higher capacity cards. While theoretically there is a 2 GB ceiling on memcard capacity, most third party memcards were at most 64 MB. If test results can be produced for higher capacities, they will be listed. Otherwise, only sizes 64 MB and under will be included.
Title | Serials/Regions Known | Known Good Capacities | Known Bad Capacities | Untested |
---|---|---|---|---|
Call of Duty: World at War - Final Fronts | SLUS-21746 | 8 MB | 32 MB | 16 MB, 64 MB |
Quake III: Revolution | SLUS-20167 | 8 MB | 32 MB | 16 MB, 64 MB |
Sonic Riders | 8 MB, 16 MB, 32 MB | 64 MB | ||
The Punisher | SLUS-20864 | 8 MB | 32 MB | 16 MB, 64 MB |
A number of games have been found over the years to contain behavior which is dangerous to memcards.
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 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.
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.
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 |
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.
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.
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 |
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 |
Starting with the PS1 analog pad and continuing on to the DualShock 2, controllers have two vibration motors, small and large. When games poll the controller, they include up to two bytes which tell the controller how much power to send to each motor. They are controlled by the 3rd and 4th (zero indexed) command bytes of a pad poll.
The mapping command itself is already described earlier in this document as part of the command list; this section will review how that affects pad polls.
Take the following pad poll command for a PS1 analog pad:
Byte (Zero Indexed) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
Command | 0x01 | 0x42 | 0x00 | 0x01 | 0xFF | 0x00 | 0x00 | 0x00 | 0x00 |
Data | 0xFF | 0x41 | 0x5A | 0xFF | 0xFF | 0x7F | 0x7F | 0x7F | 0x7F |
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).
Byte (Zero Indexed) | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Command | 0x01 | 0x42 | 0x00 | 0x00 | 0x01 |
Data | 0xFF | 0x41 | 0x5A | 0xFF | 0xFF |
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 | 0x01 | 0x00 |
Data | 0xFF | 0x41 | 0x5A | 0xFF | 0xFF |
While reversing the vibration bytes is in-spec, the utility of this is questionable. A good analogy would be to think of a pipeline between vibration commands being sent as parameters using SDK functions on the EE, and the actual vibration motors electrically kicking on. Think of everything between them as a black box for now.
You could describe this as a set of parallel lines. Left line for small motor, right line for large motor. Suppose the mapping is reversed like above, effectively all that has changed is that instead of a set of parallel lines, you now have a double-helix like the shape of DNA. The lines are now curved over each other twice, but both still arrive at the same destination with the same values as before. The game twists the lines over to the wrong side, and then the controller untwists them back to the right side again. Another way to phrase it would be that the game says to the controller "I am going to send them backwards", and the controller replies "Okay, I will read them backwards".
The most likely guess for why this is a feature at all is in the event that a developer only wants to use one of the two motors, they can accomplish that by disabling one of them in the mapping. This is done by passing 0xFF in to the respective motor in the vibration config command.
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.
The choice to use analog sticks at all or at specific times on the PS2 is left entirely to the game to decide. There are many games which may choose to not enable analog sticks at all, and others which enabled them but may for example ignore them on certain menus.
The following table tracks the following:
Title | Serials/Regions Known | Label | Used | Toggle | Notes |
---|---|---|---|---|---|
PS2 BIOS | All Revisions | N/A | No | No | |
Armored Core 2 | No | No | No | ||
Armored Core 3 | No | No | No | ||
Bloody Roar 4 | No | No | No | ||
Dragonball Z: Budokai Tenkaichi 3 | Yes | Yes | No | Ignores analogs in menus | |
Guilty Gear XX Accent Core Plus | No | Yes | No | In-game option to enable analog, default off | |
Mortal Kombat: Deadly Alliance | No | No | No | ||
Onimusha: Warlords | No | No | No | ||
Street Fighter EX3 | Yes | No | No | Game manual states both sticks are not used. | |
Tekken 4 | SLUS-20328 | No | No | No | |
Virtua Fighter 4 | Yes | No | No | ||
Virtua Fighter 4 Evolution | Yes | No | No |
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 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.
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 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 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 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.
Donald Duck: Goin' Quackers rejects all multitaps. The port does not matter, the populated slots do not matter. If a multitap is present, then the game will hang on boot.
It is certain the game is initializing libmtap; without it, a multitap plugged in to the system is essentially a forwarding agent which blindly sends all incoming traffic to slot A, until it is told by the PS2 to switch its slot. A game which does not initialize libmtap cannot actually see that a multitap is present.
Intentions are unclear though. It would be easy to attribute this to deliberate developer checks, but developers taking deliberate action to hang the game with no warnings or feedback would be a serious QA failure. Probably the more likely answer is that this is an issue implementing libpad and libmtap, leading into some serious undefined behavior. The game also hangs on boot if any non-DS2 controller is present, or if port 1 is empty. Both of these details hint towards some kind of implementation issue rather than purposeful action on the developer.
Reports suggest the same is also true of Donald Duck: Quack Attack, however this has not been hardware tested to confirm.
Provides information on the entire PS2 memcard filesystem.
Absolutely critical in making heads or tails of the PS2's IOP modules for SIO2, memcards, and pads.
Provides a full user-level breakdown of Soul Calibur III's issues with save files.
Provides both hardware level and protocol information on PS2 controllers. There are inaccuracies around the protocol details; make sure to cross reference this document with others.