TZX FORMAT |
1. | Introduction |
TZX is a file format designed to preserve all (hopefully) of the tapes
with turbo or custom loading routines. Even though some of the newer
and 'smarter' emulators can find most of the info about the loader from
the code itself, this isn't possible if you want to save the file to
tape, or to a real Spectrum. And with all this information in the file,
the emulators don't have to bother with finding out the timings and
other things. This file format is explicitly targeted to the ZX Spectrum compatible computers only. Specialized versions of the TZX format have been defined for other machines too, e.g. the Amstrad CPC and C64, but they are now available as distinct file formats with other filename extensions. At the end of this document you can find a description of encoding differences between these machines and a table which displays timings used by their respective ROM loading routines (some of them are not official). If you know of any other machines that have similar encoding that could be represented with this file format then let us know. If you're looking for TZX files, you can find an extensive collection at Martijn van der Heide's 'World of Spectrum'. The format was first started off by Tomaz Kac who was maintainer until revision 1.13, and then passed to Martijn v.d. Heide. After that, Ramsoft were the maintainers for a brief period during which the v1.20 revision was put together. If you have any questions about the format, visit the forums at World of Spectrum and ask. The default format file extension is "TZX" and hopefully this won't have to change in the future; for RISC OS, the current TAP file type will be used. Amstrad CPC files should use the extension "CDT" to distinguish them from the ZX Spectrum files, otherwise the inner structure is totally the same. |
2. | Rules and definitions |
|
3. | TZX file format |
The file is identified with the first 8 bytes being 'ZXTape!' plus the 'end of file' byte 26 (1A hex). This is followed by two bytes containing the major and minor version numbers. To be able to use a TZX file, your program (emulator, utility, or whatever) must be able to handle files of at least its major version number. If your program can handle (say) version 1.05 and you encounter a file with version number 1.06, your program must be able to handle it, even if it cannot handle all the data in the file. Then the main body of the file follows. It consists of a mixture of blocks, each identified by an ID byte. TZX block ID list:
This block must be replayed with the standard Spectrum ROM timing values - see the values in curly brackets in block ID 11. The pilot tone consists in 8063 pulses if the first data byte (flag byte) is < 128, 3223 otherwise. This block can be used for the ROM loading routines AND for custom loading routines that use the same timings as ROM ones do. Return to ID list - Return to index
This block is very similar to the normal TAP block but with some additional info on the timings and other important differences. The same tape encoding is used as for the standard speed data block. If a block should use some non-standard sync or pilot tones (i.e. all sorts of protection schemes) then use the next three blocks to describe it. Return to ID list - Return to index
This will produce a tone which is basically the same as the pilot tone in the ID 10, ID 11 blocks. You can define how long the pulse is and how many pulses are in the tone. Return to ID list - Return to index
This will produce N pulses, each having its own timing. Up to 255 pulses can be stored in this block; this is useful for non-standard sync tones used by some protection schemes. Return to ID list - Return to index
This is the same as in the turbo loading data block, except that it has no pilot or sync pulses. Return to ID list - Return to index
This block is used for tapes which have some parts in a format such that the turbo loader block cannot be used. This is not like a VOC file, since the information is much more compact. Each sample value is represented by one bit only (0 for low, 1 for high) which means that the block will be at most 1/8 the size of the equivalent VOC. The preferred sampling frequencies are 22050 or 44100 Hz (158 or 79 T-states/sample). Please, if you can, don't use other sampling frequencies. Please use this block only if you cannot use any other block. Return to ID list - Return to index
This block contains a sequence of raw pulses encoded in CSW format v2 (Compressed Square Wave). For a complete description of the CSW compression format, see the CSW documentation. Return to ID list - Return to index
This block has been specifically developed to represent an extremely wide range of data encoding techniques. The basic idea is that each loading component (pilot tone, sync pulses, data) is associated to a specific sequence of pulses, where each sequence (wave) can contain a different number of pulses from the others. In this way we can have a situation where bit 0 is represented with 4 pulses and bit 1 with 8 pulses.
The alphabet is stored using a table where each symbol is a row of pulses. The number of columns (i.e. pulses) of the table is the length of the longest sequence amongst all (MAXP=NPP or NPD, for pilot/sync or data blocks respectively); shorter waves are terminated by a zero-length pulse in the sequence. Any number of data symbols is allowed, so we can have more than two distinct waves; for example, imagine a loader which writes two bits at a time by encoding them with four distinct pulse lengths: this loader would have an alphabet of four symbols, each associated to a specific sequence of pulses (wave).
Most commonly, pilot and sync are repetitions of the same pulse, thus they are represented using a very simple RLE encoding structure which stores the symbol and the number of times it must be repeated. Each symbol in the data stream is represented by a string of NB bits of the block data, where NB = ceiling(Log2(ASD)). Thus the length of the whole data stream in bits is NB*TOTD, or in bytes DS=ceil(NB*TOTD/8). Example A typical Spectrum's standard loading header can be represented like this:
The very same data information encoded to work with the ZX81 would look like this:
Return to ID list - Return to index
This will make a silence (low amplitude level (0)) for a given time in milliseconds. If the value is 0 then the emulator or utility should (in effect) STOP THE TAPE, i.e. should not continue loading until the user or emulator requests it. Return to ID list - Return to index
This block marks the start of a group of blocks which are to be treated as one single (composite) block. This is very handy for tapes that use lots of subblocks like Bleepload (which may well have over 160 custom loading blocks). You can also give the group a name (example 'Bleepload Block 1'). For each group start block, there must be a group end block. Nesting of groups is not allowed. Return to ID list - Return to index
This indicates the end of a group. This block has no body. Return to ID list - Return to index
This block will enable you to jump from one block to another within the file. The value is a signed short word (usually 'signed short' in C); Some examples:
Return to ID list - Return to index
If you have a sequence of identical blocks, or of identical groups of blocks, you can use this block to tell how many times they should be repeated. This block is the same as the FOR statement in BASIC. For simplicity reasons don't nest loop blocks! Return to ID list - Return to index
This is the same as BASIC's NEXT statement. It means that the utility should jump back to the start of the loop if it hasn't been run for the specified number of times. This block has no body. Return to ID list - Return to index
This block is an analogue of the CALL Subroutine statement. It basically executes a sequence of blocks that are somewhere else and then goes back to the next block. Because more than one call can be normally used you can include a list of sequences to be called. The 'nesting' of call blocks is also not allowed for the simplicity reasons. You can, of course, use the CALL blocks in the LOOP sequences and vice versa. The value is relative for the obvious reasons - so that you can add some blocks in the beginning of the file without disturbing the call values. Please take a look at 'Jump To Block' for reference on the values. Return to ID list - Return to index
This block indicates the end of the Called Sequence. The next block played will be the block after the last CALL block (or the next Call, if the Call block had multiple calls). Again, this block has no body. Return to ID list - Return to index
This block is useful when the tape consists of two or more separately-loadable parts. With this block, you are able to select one of the parts and the utility/emulator will start loading from that block. For example you can use it when the game has a separate Trainer or when it is a multiload. Of course, to make some use of it the emulator/utility has to show a menu with the selections when it encounters such a block. All offsets are relative signed words. Return to ID list - Return to index
When this block is encountered, the tape will stop ONLY if the machine is an 48K Spectrum. This block is to be used for multiloading games that load one level at a time in 48K mode, but load the entire tape at once if in 128K mode. This block has no body of its own, but follows the extension rule. Return to ID list - Return to index
This block sets the current signal level to the specified value (high or low). It should be used whenever it is necessary to avoid any ambiguities, e.g. with custom loaders which are level-sensitive. Return to ID list - Return to index
This is meant to identify parts of the tape, so you know where level 1 starts, where to rewind to when the game ends, etc. This description is not guaranteed to be shown while the tape is playing, but can be read while browsing the tape or changing the tape pointer. The description can be up to 255 characters long but please keep it down to about 30 so the programs can show it in one line (where this is appropriate). Please use 'Archive Info' block for title, authors, publisher, etc. Return to ID list - Return to index
This will enable the emulators to display a message for a given time. This should not stop the tape and it should not make silence. If the time is 0 then the emulator should wait for the user to press a key. The text message should:
Return to ID list - Return to index
Use this block at the beginning of the tape to identify the title of the game, author, publisher, year of publication, price (including the currency), type of software (arcade adventure, puzzle, word processor, ...), protection scheme it uses (Speedlock 1, Alkatraz, ...) and its origin (Original, Budget re-release, ...), etc. This block is built in a way that allows easy future expansion. The block consists of a series of text strings. Each text has its identification number (which tells us what the text means) and then the ASCII text. To make it possible to skip this block, if needed, the length of the whole block is at the beginning of it. If all texts on the tape are in English language then you don't have to supply the 'Language' field The information about what hardware the tape uses is in the 'Hardware Type' block, so no need for it here. Return to ID list - Return to index
This blocks contains information about the hardware that the programs on this tape use. Please include only machines and hardware for which you are 100% sure that it either runs (or doesn't run) on or with, or you know it uses (or doesn't use) the hardware or special features of that machine. If the tape runs only on the ZX81 (and TS1000, etc.) then it clearly won't work on any Spectrum or Spectrum variant, so there's no need to list this information. If you are not sure or you haven't tested a tape on some particular machine/hardware combination then do not include it in the list. The list of hardware types and IDs is somewhat large, and may be found at the end of the format description. Return to ID list - Return to index
This block can be used to save any information you want. For example, it might contain some information written by a utility, extra settings required by a particular emulator, or even poke data. Return to ID list - Return to index
This block is generated when you merge two ZX Tape files together. It is here so that you can easily copy the files together and use them. Of course, this means that resulting file would be 10 bytes longer than if this block was not used. All you have to do if you encounter this block ID is to skip next 9 bytes. If you can avoid using this block for this purpose, then do so; it is preferable to use a utility to join the two files and ensure that they are both of the higher version number. Return to ID list - Return to index |
4. | Hardware information reference |
This is the list of all hardware types and hardware identification ID's that are used in the 'Hardware info' block. Please send any additions you might have to the TZX maintainers so that they can be included. By default you don't have to write any of the information if the game is made for the ZX Spectrum and complies with the following:
If the game is 128K ONLY then you would include two entries: The game works on AND uses the hardware of a 128K Spectrum AND the game DOESN'T work on a 48K Spectrum. If the game works on both 48K and 128K Spectrum, but it only uses the sound chip (AY) of the 128K Spectrum and none of its extra memory then you would only include the entry that says that the game uses the 'Classic AY hardware (Spectrum 128 sompatible sound device)'. These were only some examples of the usage of this block.
|
5. | Machine specific information |
Currently supported machines are: ZX Spectrum, Amstrad CPC, SAM Coupe, ZX-81 Jupiter ACE and Enterprise. Only ZX-81 (or the old Timex 1000) and Jupiter ACE use different tape encoding than the others.
|
6. | Deprecated blocks |
The following blocks, which were in the format until revision 1.13 (inclusive),
have now been deprecated and they should not appear in TZX files v1.20
and above.
Their structure is documented here for completeness, to allow general
tools and emulators to maintain full backward compatibility with old
TZX files.
However note that these blocks have not proven to be useful and,
as a consequence, it appears that almost no existing TZX files contain them.
Well, this block was created to support the Commodore 64 standard ROM and similar tape blocks. It is made so basically anything that uses two or four pulses (which are the same in pairs) per bit can be written with it. Some explanation:
Return to deprecated ID list - Return to index
This block is made to support another type of encoding that is commonly used by the C64. Most of the commercial software uses this type of encoding, i.e. the Pilot tone is not made from one type of Wave only, but it is made from actual Data byte which is repeated many times. As the Sync value another, different, Data byte is sent to signal the start of the data. The Data Bits are made from ONE wave only and there is NO XOR checksum either! Trailing byte is played AFTER the DATA has ended. Return to deprecated ID list - Return to index
This is a special block that would normally be generated only by emulators. For now it contains info on everything I could find that other formats support. Please inform me of any additions/corrections since this is a very important part for emulators. Those bits that are not used by the emulator that stored the info, should be left at their DEFAULT values. Return to deprecated ID list - Return to index Some of the most common uses of the Custom info block (ID 35) have become standardized in the past revisions, although now they are deprecated:
Return to deprecated ID list - Return to index
This would enable one to snapshot the game at the start and still have all the tape blocks (level data, etc.) in the same file. Only .Z80 and .SNA snapshots are supported for compatibility reasons! The emulator should take care of that the snapshot is not taken while the actual Tape loading is taking place (which doesn't do much sense). And when an emulator encounters the snapshot block it should load it and then continue with the next block. Return to deprecated ID list - Return to index |
7. | Revision history |
Revision 1.20
Revision 1.13
Revision 1.12
Revision 1.10
Revision 1.02
Revision 1.01
|