Wondercard  v0.2.1
A fully virtual emulation of the protocol used by Memory Cards for the PlayStation.
Wondercard

A fully virtual emulation of the protocol used by Memory Cards for the PlayStation.

This is a application-layer emulation of the Memory Card protocol, therefore the miscellany of the SPI protocol used at the signal level to communicate between the PlayStation and Memory Card is not represented exactly.

Instead we limit our representation to a model where bytes are sent to and from the virtual memory card, and provide a basic representation of Z-state (high impedance) inputs/outputs on the MOSI/MISO lines and a way to represent a missing card (ACK line never brought low).

Installation

This project builds with CMake v3.15+ on recent versions of Linux, macOS and Windows. You need a compiler supporting some C++20 features to build it.

cd build # or whatever other place you want to compile
cmake ..
make
make install # optional

Usage

Everything lives in the com::saxbophone::wondercard namespace.

The current functionality comprises a virtual MemoryCard class which implements the logic found on memory cards, and a virtual MemoryCardSlot class for reading and writing the cards.

Complete Intro Demo

#include <array>
int main() {
using namespace com::saxbophone;
/*
* Fill the whole card with value 0x13
* We can use any other type for the container as long as it is convertible
* to std::span
*/
std::array<wondercard::Byte, wondercard::MemoryCard::CARD_SIZE> card_data;
card_data.fill(0x13);
// initialise card with data
wondercard::MemoryCard card(card_data);
wondercard::MemoryCardSlot slot;
// we must insert the card into the slot before we can read or write it
if (not slot.insert_card(card)) {
return -1; // failed to insert card
}
// read card data back out
std::array<wondercard::Byte, wondercard::MemoryCard::CARD_SIZE> read_data;
if (not slot.read_card(read_data)) {
return -1; // read failure
}
// read data should be identical to card data
if (not (read_data == card_data)) {
return -1;
}
// we can also write data to the card, or write just specific parts of it
std::array<wondercard::Byte, wondercard::MemoryCard::SECTOR_SIZE> sector = {
0x13, 0x14, 0x15, 0x16, 0xCD, 0xBC, 0xB6, 0xB9, /* remainder unspecified */
};
// use sector values 0..1023 / 0x000..0x3FF
if (not slot.write_sector(0x115, sector)) {
return -1; // read failure
}
slot.remove_card();
}

If the default constructor for MemoryCard is used, then the card is initialised with all-zero data.

Reading and writing cards is supported for the entire card, by Block (analogous to the save blocks used by the PlayStation card manager) and by Sector. A Card is divided into 16 Blocks, each of these being divided into 64 Sectors. Here is a table of Card, Block and Sector size conversions:

Row per Column Card Block Sector
Block 16 1 N/A
Sector 1024 64 1
Byte 128KiB 8192 128

API Reference

Online Documentation

The docs site is separated by minor version. You can access documentation for other versions of the project by changing the v*.* part of the URL. Currently, only minor versions are intended to be compatible with eachother.