The ZXS File Format |
With version 0.99 of zx32 a new file format (ZXS) was introduced, and enhanced in versions 1.01 and 1.02. This is meant to replace all the other Spectrum-related file formats in existence (NOT!J). ZXS files use the Resource Interchange File Format (RIFF). The following is an excerpt adapted from the Microsoft® Multimedia API (MAPI) Programmer's Guide.
RIFF files use four-character codes to identify file elements. These codes are 32-bit quantities representing a sequence of one to four ASCII alphanumeric characters, padded on the right with space characters.
The basic building block of a RIFF file is a chunk. A chunk is a logical unit of multimedia data, such as a single frame in a video clip. Each chunk contains the following fields:The following illustration shows a "RIFF" chunk that contains two subchunks.
- A four-character code specifying the chunk identifier
- A doubleword value specifying the size of the data member in the chunk
- A data field
A chunk contained in another chunk is a subchunk. The only chunks allowed to contain subchunks are those with a chunk identifier of "RIFF" or "LIST". A chunk that contains another chunk is called a parent chunk. The first chunk in a RIFF file must be a "RIFF" chunk. All other chunks in the file are subchunks of the "RIFF" chunk.
"RIFF" chunks include an additional field in the first four bytes of the data field. This additional field provides the form type of the field. The form type is a four-character code identifying the format of the data stored in the file. For example, Microsoft waveform-audio files have a form type of "WAVE".
"LIST" chunks also include an additional field in the first four bytes of the data field. This additional field contains the list type of the field. The list type is a four-character code identifying the contents of the list. For example, a "LIST" chunk with a list type of "INFO" can contain "ICOP" and "ICRD" chunks providing copyright and creation date information. The following illustration shows a "RIFF" chunk that contains a "LIST" chunk and one other subchunk (the "LIST" chunk contains two subchunks).
ZXS files have a form type of "SNAP". Subchunks that are defined, for now, are:
"fmtz" |
File format information#define ZXM_DEFAULT_ 0 #define ZXM_048K____ 0x0010 // ZX Spectrum 48K (Model 2) #define ZXM_048K_P__ 0x0020 // ZX Spectrum + (Model 3) #define ZXM_128K____ 0x0030 // ZX Spectrum 128 #define ZXM_128K_P2_ 0x0040 // ZX Spectrum +2 #define ZXM_128K_P2A 0x0050 // ZX Spectrum +2A #define ZXM_128K_P3_ 0x0060 // ZX Spectrum +3 #define ZXH_NONSTANDARD 0x0001 // peripheral hardware #define ZIP_STORED 0 // compression methods #define ZIP_SHRUNK 0x0001 #define ZIP_REDUCED1 0x0002 #define ZIP_REDUCED2 0x0003 #define ZIP_REDUCED3 0x0004 #define ZIP_REDUCED4 0x0005 #define ZIP_IMPLODED 0x0006 #define ZIP_TOKENIZED 0x0007 #define ZIP_DEFLATED 0x0008 #define ZIP_NOTZIPPED 0xFFFF typedef struct _ZIPCHUNKHEADER { DWORD dwSize // structure size DWORD dwCRC32; // crc DWORD dwLength; // uncompressed size } ZIPCHUNKHEADER; typedef struct _FMTZ { WORD wVersion; WORD wHardwareModel; WORD wHardwareFlags; WORD wCompressionMethod; } FMTZ; wVersion is the file format version, with the
high-order byte specifying the major version number and
the low-order byte specifying the minor version
(revision). The current file format version is 0x0101
(i.e., 1.01). In general, an emulator shouldn't attempt
to read the rest of the subchunks if the major file
version is greater than the one it knows about. The user
should be warned if the minor file version is greater
than the one supported. Additionally, the value stored
should be the lowest possible. For example if disk
subchunks are not present 0x0100 (1.00) should be used. |
"rZ80" |
Z80 processor registerstypedef struct _RZ80 { WORD zFA; WORD zBC; WORD zDE; WORD zHL; WORD _zFA; WORD _zBC; WORD _zDE; WORD _zHL; WORD zIX; WORD zIY; WORD zPC; WORD zSP; BYTE zI; BYTE zR; BYTE zIFF1; BYTE zIFF2; BYTE zIM; DWORD dwTicks; } RZ80; dwTicks is the number of the Z80 clock ticks elapsed since the last interrupt occurred. The function of the other members of this structure should be obvious. |
"r048" |
48K I/O buffertypedef struct _R048 { BYTE bufULA; BYTE bufKey[8]; } R048; bufULA holds the last byte written to a ULA
port and can be used to determine the border color. |
"r128" |
128K I/O buffertypedef struct _R128 { BYTE buf7FFD; BYTE bufFFFD; BYTE bufPSG[16]; } R128; buf7FFD holds the last value sent to port
0x7FFD and can be used to determine the memory
organization in effect. |
"r+3 " |
+2A|+3 I/O buffertypedef struct _RPL3 { BYTE buf1FFD; } RPL3; buf1FFD holds the last value sent to port
0x1FFD and can be used to determine the extended memory
organization in effect. |
"ram0".. "ram7" |
Memory pagesFor 48K snapshots "ram5", "ram2" and "ram0" subchunks should be present. They should hold the memory contents at address 0x4000, 0x8000 and 0xC000 respectively. |
"tape" |
Tape imagetypedef struct _TAPE { DWORD dwCurrentPosition; DWORD dwRemainBlockLength; DWORD dwDataSize; BYTE cbData[1]; } TAPE; The format utilized for cbData is the TAP file format, as defined by Gerton Lunter for the Sinclair ZX Spectrum Emulator Z80, and adopted by many other emulators. |
"dsk0".. "dsk1" |
Disk imagesThese should reflect disks inserted in drive 0 and 1 respectively. The presence of "dsk1" is not recommended unless absolutely necessary. In fact it shouldn't be present unless "dsk0" already exists. |
"zx32" |
Reserved for use by zx32Other emulators can reserve a subchunk for their own requirements, provided that the name selected:
Please contact me if you'd like to reserve a subchunk or define one for common use. Do NOT feel free to extend the file format to suit your needs, in any other way. |
All structures are packed at an 1-byte boundary (that is, alignment of structure fields is disabled)), and values are stored with LSB first (this is inherent in the RIFF specification - subchunk sizes are stored this way, too). As any structure may be expanded in the future, data should be loaded based on the supported structure size and not the size of the subchunk. For example
mmioRead(hmmio, (HPSTR)&fmtz, ck.cksize); // WRONG! mmioRead(hmmio, (HPSTR)&fmtz, sizeof(FMTZ)); // CORRECT
Note also that RIFF subchunks can not have an odd size - a null byte is appended in that case. Windows MMIO procedures do this automatically, but if you are writing your own you should bear this in mind.
Subchunks may be saved in any order. None of them is required, but the presence of one may imply the presence of another. If "r048" is present then "rZ80", "ram5", "ram2" and "ram0" need be present, and "r048", "rZ80" and "ram0".."ram7" must be included with "r128". The presence of the "fmtz" subchunk is strongly recommended. It is definitely required if compression is used, a +2A or +3 is emulated or any non-standard (i.e., all of themJ) hardware peripheral is present. I have to state again here, that the file version number stored should be the lowest possible.
The ZXS file extension is not obligatory, but the "zx" prefix is, in order for the file type to be clearly related with a ZX Spectrum emulator. For example, if only the "tape" chunk is present, the extension could be ZXT or zxtape. ZXD or zxdisk are the recommended extensions for disk-only files.
The only compression methods supported by zx32 are ZIP_STORED and ZIP_DEFLATED. The rest of the compression methods are old and inefficient and their use limited by copyrights and patents. They are defined and can be used if necessary, nonetheless.
Since version 1.03, zx32 supports standard "INAM", "ICOP", "ICRD", "IGNR", "IKEY" and "ICMT" subchunks of LIST chunks with a list type of "INFO". Most of them are useful mainly to search engines; any other standard subchunk may be used; and the Comments("ICMT") subchunk should be able to cover a large area of needs. It's highly probable that no extra information subchunks will be defined, therefore.
In version 1.01 of the file format specification "dsk0".."dsk1" subchunks are defined.
In version 1.00 "fmtz" and "r+3 " subchunks were defined.
Last Revised: February 16, 2000. |
Home |