![]() |
libElysianVMU 1.6.0
Full-featured, accurate, cross-platform library emulating the Dreamcast's Visual Memory Unit
|
Flash 8-Bit FAT Filesystem Layout.
A formatted VMU's flash contains a fairly standard 8-bit FAT filesystem, used by the memory card functionality to store DATA and GAME files.
Flash memory is split into a series of equal-sized "blocks", which is the smallest unit of data which can be read from or written to flash. A standard-sized VMU has 256 total blocks of 512 bytes each, giving a total capacity of 128KB.
The following is the generalized memory map of the flash address space for a single formatted VMU partition, along with its contents and region names:
Block | Contents | Region |
---|---|---|
0 | Game File | User |
... | ||
... | ||
... | Data Files | |
... | ||
... | ||
... | ||
... | ||
... | ||
... | ||
... | Reserved | Hidden |
... | ||
... | ||
... | ||
... | ||
... | Directory | System |
... | ||
... | ||
... | FAT | |
N | Root |
The system region comprises three different subregions: the Root block, the FAT blocks, and the Directory blocks. All three must be present and correctly configured for a well-behaved filesystem.
The Root block (or Superblock) is essentially a single block which is reserved for describing the volume and the layout of its filesystem regions. It is typically located within the last indexable block of the filesystem.
Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x000 | ||||||||||||||||
0x010 | ||||||||||||||||
0x020 | ||||||||||||||||
0x030 | ||||||||||||||||
0x040 | Volume Last | FAT Size | DIR Last | DIR Size | Icon | Sort | ||||||||||
0x050 | Hidden First | Hidden Size | Game First | Game Size | ||||||||||||
0x060 | ||||||||||||||||
... | ||||||||||||||||
0x1F0 |
[0x000] Magic (16 bytes):
A 16-byte region where the byte value 0x55
must be repeated in order to signify that the volume is properly formatted and initialized to the VMU and Dreamcast BIOSes.
[0x010] Volume Label (32 bytes):
From the Maple protocol's perspective, the Volume Label is described as being an arbitrary user identifier for the volume, which can contain anything. In reality, it's not used by the VMU, but it has the following specific format for the Dreamcast's BIOS:
Offset | Size | Name | Description |
---|---|---|---|
0x00 | 1 | custom_color | Set to 0x01 if using custom volume color, otherwise 0x00 . |
0x01 | 1 | blue | 0-255 value for the blue channel of the custom volume color. |
0x02 | 1 | green | 0-255 value for the green channel of the custom volume color. |
0x03 | 1 | red | 0-255 value for the red channel of the custom volume color. |
0x04 | 1 | alpha | 0-255 value for the alpha channel of the custom volume color (0 : opaque, 255 : transparent). |
0x05-0x20 | 27 | unused | All bytes set to 0x00 . |
[0x030] Timestamp (8 bytes):
The date and time at which the VMU was last formatted.
Offset | Size | Name | Description |
---|---|---|---|
0x00 | 1 | century | First two digits of the AD year (00-99 ). |
0x01 | 1 | year | Last two digits of the AD year (00-99 ). |
0x02 | 1 | month | Month (1=Jan thru 12=Dec ). |
0x03 | 1 | day | Day of the month (1-31 ). |
0x04 | 1 | hour | Hour of the day (0-23 ). |
0x05 | 1 | minute | Minute of the hour (0-59 ). |
0x06 | 1 | second | Second of the minute (0-59 ). |
0x07 | 1 | week_day | Day of the week (0=Mon thru 6=Sun ) |
[0x040] Volume Last (2 bytes):
The last indexable block on the volume or total # of blocks in the volume minus 1. (default: 255
).
[0x042] Partition (2 bytes):
Partition # for this volume (default: 0x00
).
[0x044] Root (2 bytes):
Block # of (this) root block (default: 255
).
[0x046] FAT First (2 bytes):
Block # of the first FAT block (default: 254
).
[0x048] FAT Size (2 bytes):
Size (in blocks) of the FAT region (default: 1
).
[0x04a] DIR Last (2 bytes):
Block # of the last Directory block (default: 253
).
[0x04c] DIR Size (2 bytes):
Size (in blocks) of the Directory region (default: 13
).
[0x04e] Icon (1 byte):
VMU volume icon as displayed within the Dreamcast's BIOS (values: 0-123
).
[0x04f] Sort (1 byte):
Unknown or unused flag (default: 0x00
).
[0x050] Hidden First (2 bytes):
Block # of the first Hidden block (default: 200
).
[0x052] Hidden Size (2 bytes):
Size (in blocks) of the Hidden region (default: 31
).
[0x054] Game First (2 bytes):
Block # where the first block of a GAME file must be written (default: 0
).
[0x056] Game Size (2 bytes):
Largest size (in blocks) of a GAME file (default: 128
).
[0x058] Reserved (408+ bytes):
Claimed to be reserved, all filled with 0x00
; however, it's unlikely that these bytes actually have to be zero'd out. Most likely they can be used for arbitrary storage.
The File Allocation Table (FAT) subregion within the filesystem is a contiguous array of entries, starting at the block given by FAT First
and growing upwards to the block located at FAT First + FAT Size - 1
.
The FAT contains a 16-bit FAT entry for every block in the filesystem, meaning its size should be 2 * Total Number of Blocks / Block size
, or 1 block for the default 256 block VMU volume.
The address of a given block's FAT entry is calculated by: Fat Entry for Block N = Fat First * Block Size + 2 * N
.
Each FAT Entry contains one of the following values:
Value | Name | Description |
---|---|---|
0xfffc | Unallocated | The block is unused or free. |
0xffff | Damaged | The block has been damaged and its contents are to be allocated from the Hidden region. |
0xfffa | Last In File | The block is the last one within its file and has no next block. |
Other | Next In File | The block is proceeded by the another block in the file. |
The FAT Entry should immediately tell you whether a block is in-use, free, or damaged. In the case of an in-use block, its FAT Entry should always contain the block # of the next block in the file sequence, creating a linked-list of blocks, whose next pointers are its FAT Entries, with the final block within the file terminating with a FAT Entry value of 0xfffa
.
0xfffa
. The FAT Entries for the FAT should form a linked-list starting at FAT First
, with each Entry pointing to the next block in the sequence up to the last block, which should be terminated with 0xfffa
. The FAT Entries for the Directory should be linked in a similar fashion; however, they point in the opposite direction, as the Directory grows from highest-to-lowest block order.The Directory is a subregion within the System region which contains the file-listing for all files present within the filesystem. The Directory is divided into a series of Directory Entries.
200 * 32
= 6400 bytes / 512
bytes per block = 12.5 Directory blocks, or rounded up, the default value of 13
for a freshly formatted VMU.Each 32-byte Directory Entry has the following format:
Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x000 | Type | Copy | Start FAT | |||||||||||||
0x010 | Size | Header |
[0x000] Type (1 byte):
The type of file described by the Directory Entry:
0x00
: None0x33
: Data0xcc
: Game [0x001] Copy (1 byte):
Whether the file can be copied or not (from within the Dreamcast or VMU BIOS menus):
0xff
: Copy Protected[0x002] Start FAT (2 bytes):
The first block containing the file data. Subsequent blocks are determined by following each block's FAT Entries.
[0x004] Filename (12 bytes):
Name of the file in Shift-JIS encoding WITHOUT NULL
termination!
[0x010] Timestamp (8 bytes):
Date + time of the last time the file was written to, in the same BCD 8-byte format as in the Root Block.
[0x008] Size (2 bytes):
The size of the file in blocks.
[0x00a] Header (2 bytes):
The location of the VMS header structure within the file, relative to the first FAT Entry of the file.
[0x00c] Reserved (4 bytes):
All set to 0x00
.
The hidden region is a special reserved region for storing information as the regular VMU blocks of other regions slowly wear out and can no longer be written to successfully. This storage redundancy is meant to be a mechanism to extend the flash's lifespan.
When a block within another region is no loner viable, it is marked with a value of 0xffff
within its FAT Entry, and the storage for the block can be allocated from the Hidden Region.
When a block within the FAT becomes damaged, the entire FAT must be relocated to the Hidden Region, as it must be stored within a contiguously-allocated set of blocks.
When the entire Hidden Region becomes used, blocks at the high-end of the User Region begin being used, as the total capacity of the VMU's volume slowly becomes reduced.
The User Region designates the area where regular user-visible files are stored. Two different types of user files exist: DATA and GAME files, each with different layout requirements.
Data files are typically save files from Dreamcast games. Their blocks are allocated from the highest to the lowest block within the User Region. Their blocks do not need to be contiguous and can jump around, as the FAT Entry for each block will point to its next block. There is also no limit on the number of data files which can be stored within a VMU (although realistically the size of the Directory and number of entries within it will become a bottleneck).
Game files are special files which can be executed from the VMU when used in standalone mode. These are typically in the form of minigames which get saved from a main Dreamcast game. Only one of these files may be present at a time on a single volume. Furthermore, each game file must be allocated starting at block 0, growing CONTIGUOUSLY up towards the Game Size
limit set within the Root Block.