VMU memory organization
The VMS flash memory contains 128 kilobytes of storage. These are
divided into 256 blocks of 512 bytes each. Of these blocks, 200 are
available for user files. The rest of the blocks contain filesystem
information, or are simply not used at all.
The allocation of the 256 blocks is as follows:
0
.
.
.
199 |
User data (files) |
200
.
.
.
240 |
Not used |
241
.
.
.
253 |
Directory |
| 254 |
FAT |
| 255 |
Root block |
|
The Directory, FAT and Root block are system files. They
are not listed in the Directory, but do appear in the FAT. The Root
block is always block 255. The start block of the FAT and Directory
can be found in the Root block, see below.
The root block (block 255) contains information such as:
- The date when the card was formatted
- The color and icon for this VMS in the Dreamcast file manager
- Location and size of the FAT and Directory system files
I'm not sure about the actual format of this block, apart from the
following:
0x000-0x00f : All these bytes contain 0x55 to indicate a properly formatted card.
0x010 : custom VMS colour (1 = use custom colours below, 0 = standard colour)
0x011 : VMS colour blue component
0x012 : VMS colour green component
0x013 : VMS colour red component
0x014 : VMS colour alpha component (use 100 for semi-transparent, 255 for opaque)
0x015-0x02f : not used (all zeroes)
0x030-0x037 : BCD timestamp (see Directory below)
0x038-0x03f : not used (all zeroes)
...
0x046-0x047 : 16 bit int (little endian) : location of FAT (254)
0x048-0x049 : 16 bit int (little endian) : size of FAT in blocks (1)
0x04a-0x04b : 16 bit int (little endian) : location of directory (253)
0x04c-0x04d : 16 bit int (little endian) : size of directory in blocks (13)
0x04e-0x04f : 16 bit int (little endian) : icon shape for this VMS (0-123)
0x050-0x051 : 16 bit int (little endian) : number of user blocks (200)
...
The File Allocation Table works similar to a MS-DOS FAT16 File
Allocation Table. It serves two purposes; it indicates which blocks
are unallocated, and it links the blocks of a file together. Each of
the 256 blocks have an entry in this table consisting of a 16-bit
integer value (little endian). The entry for block 0 is stored first
in the FAT, and the entry for block 255 is stored last. The entry is
interpreted like this:
0xfffc : This block is unallocated
0xfffa : This block is allocated to a file, and is the last block in that file
0x00-0xff : This block is allocated to a file, and is not the last block in that file
In the last case, the actual value of the entry indicates the next
block in the file. This way, if the number of the first block of a
file is known, the subsequent blocks can be found by traversing the
FAT. The number of the first block can be found in the Directory if
it is a user file, or in the Super block if it is a system file.
Note that mini-game files are allocated starting at block 0 and
upwards, while a data file is allocated starting at block 199
selecting the highest available free block. This is probably
because a mini-game should be able to run directly from the flash, and
thus needs to be placed in a linear memory space starting at a known
address (i.e. 0).
Although block 200 through 240 are marked as "free" in the FAT, they
can not be used for anything.
The Directory lists all the user files stored in the VMS. The
Directory consists of a sequence of 32-byte entries each potentially
describing a file. When the VMS is formatted, enough space is
allocated to the Directory file to accommodate 200 entries. This is
enough, since each file must be at least one block long, and there are
only 200 blocks available for user files. The actual blocks making up
the Directory can be found using the Root block and the FAT, although
it should be safe to assume that the Directory has been allocated to
blocks 241 through 253; 253 being the first block of the Directory,
and 241 the last.
An entry in the directory is either all NUL-bytes (denoting an
unused entry), or a structure describing a file. This structure looks
as follows:
0x00 : 8 bit int : file type (0x00 = no file, 0x33 = data, 0xcc = game)
0x01 : 8 bit int : copy protect (0x00 = copy ok, 0xff = copy protected)
0x02-0x03 : 16 bit int (little endian) : location of first block
0x04-0x0f : ASCII string : filename (12 characters)
0x10-0x17 : BCD timestamp (see below) : file creation time
0x18-0x19 : 16 bit int (little endian) : file size (in blocks)
0x1a-0x1b : 16 bit int (little endian) : offset of header (in blocks) from file start
0x1c-0x1f : unused (all zero)
The file creation time is stored as a sequence of BCD (Binary Coded
Decimal) bytes. Each byte represents a number between 0 and 99. The
meaning of the bytes are as follows:
- Century (e.g. 19)
- Year within century (e.g. 99)
- Month within year (e.g. 11)
- Day within month (e.g. 1)
- Hour of day (e.g. 22)
- Minute of hour (e.g. 50)
- Second of minute (e.g. 12)
- Day of week (0 = monday, 6 = sunday)
The software for the "Nexus 4 meg" 3rd party memory card can transfer
the contents of the memory card flashrom to a PC and storing it in a
file designated a "DCM-file". This is basically just a raw memory
dump of the entire flashrom, however it must be noted that order of
the bytes have been reversed in groups of 4. This means that the
first byte of the file is actually the fourth byte of the flashrom,
the second byte in the file is the third byte of the flashrom and so
on.
"DCI-files" are another Nexus specific file format. A DCI-file contains
only the blocks of a single file. The first 32 bytes of the file is the
directory entry for the file (see above), exactly as it appears in the
flashrom (no byte swapping). The "location of first block" field should be
ignored when reading.
After the first 32 bytes each block of the file follows, in order.
The blocks are byte-swapped just like in a DCM-file.
All VMS files should contain a standard header which is used by the file
managers in the VMS and in the DC boot ROM to display information about
the file. (ICONDATA files use a somewhat
simplified headers since they are not shown in the DC boot ROM file manager.)
For data files, the header is stored at the very beginning of the file.
For game files, it begins in the second block of the file (offset $200).
This fact should be reflected by the header offset field in the VMS
directory, which should contain 1 for game files, and 0 for data files.
This is the contents of the header:
| Offset | Size (bytes) | Datatype | Contents |
| $00 |
16 |
Text |
Description of file (shown in VMS file menu) |
| $10 |
32 |
Text |
Description of file (shown in DC boot ROM file manager) |
| $30 |
16 |
String |
Identifier of application that created the file |
| $40 |
2 |
Integer |
Number of icons (>1 for animated icons) |
| $42 |
2 |
Integer |
Icon animation speed |
| $44 |
2 |
Integer |
Graphic eyecatch type (0 = none) |
| $46 |
2 |
Integer |
CRC (Ignored for game files.) |
| $48 |
4 |
Integer |
Number of bytes of actual file data following header, icon(s) and graphic eyecatch. (Ignored for game files.) |
| $4C |
20 |
|
Reserved (fill with zeros) |
| $60 |
32 |
Integers |
Icon palette (16 16-bit integers) |
| $80 |
512*n |
Nybbles |
Icon bitmaps |
| ... |
depends on type |
... |
Graphic eyecatch palette and bitmap |
|
Text fields are padded with space ($20). String fileds are padded with
NUL ($00). Integer fields are little endian.
The CRC should be computed on the entire file, including header and data
payload, but excluding any padding in the final block. When calcukating
the CRC, set the CRC field itself to 0 to avoid miscalculating the CRC for
the header. The CRC calculation algorithm is as follows (C code):
int calcCRC(const unsigned char *buf, int size)
{
int i, c, n = 0;
for (i = 0; i < size; i++)
{
n ^= (buf[i]<<8);
for (c = 0; c < 8; c++)
if (n & 0x8000)
n = (n << 1) ^ 4129;
else
n = (n << 1);
}
return n & 0xffff;
}
The palette consists of 16 16-bit little endian integers, one for each colour
in the palette. Each integer consists of four four-bit fields:
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Alpha |
Red |
Green |
Blue |
|
Alpha 15 is fully opaque, alpha 0 is fully transparent.
The header should contain at least one icon bitmap for the file. If an
animated icon is desired, up to three bitmaps can be used (set the field at
offset $40 accordingly). The bitmaps are stored directly after each other,
starting at offset $80.
The bitmaps contain one nybble per pixel. Each byte thus
represents two horizontally adjacent pixels, the high nybble being the
left one and the low nybble being the right one. Each complete bitmap
contains 1024 (32 * 32) nybbles, or 512 bytes.
The header can optionally contain a 72×56 pixel image shown as a graphic
eyecatch for the file in the DC boot ROM file manager. The graphic data
for the eyecatch is stored immediately after the last icon bitmap. There
are four possible visual modes, selected with the field at offset $44:
| Mode | Graphic data size (bytes) | Data format |
| 0 |
0 |
None |
| 1 |
8064 |
16-bit true colour, see Icon palette for pixel format. |
| 2 |
4544 (512 bytes palette, 4032 bytes bitmap) |
256 colour palette based. Begins with a palette in the same format as the Icon palette, but with 256 entries. Then the bitmap has one byte per pixel, giving the index into the palette. |
| 3 |
2048 (32 bytes palette, 2016 bytes bitmap) |
16 colour palette based. Format is just like the Icon palette and bitmap, except for the width and height of the bitmap of course. |
|