[FAQ]
[Frequently Asked Questions] [Resources] [Emulators] [Where Is...?] [File Formats] [Technical Information] [Pinouts] [Acknowledgements]

SPECCY EMULATOR FILE FORMATS

This page last updated on 2 May 2000

[Snapshots] [SLT] [SNA] [SNA 128] [SP] [Z80] [ZX] [ZX82] [ZXS]
[Tapes] [ITM] [TAP/BLK] [TAP (Warajevo)] [TZX]
[Disks] [DSK] [FDI] [Hobeta] [IMG] [MGT] [SCL] [TRD]
[Others] [AZX] [DCK] [MDR] [NET] [PAL] [POK] [SCR]

If you need information on a format which is not documented here, try reading the documentation which comes with a emulator which supports that format; if you are looking for some code to load/save these formats, some good sources of information are SpConv (public domain), and SnapConv (GPL)

Snapshot Files

Those handled by SPConv v1.10 are in italics:

.ACH or .archimedes Snapshots used by !Speccy. .ACH is the extension SPConv uses for these files, so that filename-challenged operating systems like DOS can handle such files for conversion purposes.
.PRG Snapshots used by SpecEm.
.RAW Raw memory dump from a real Spectrum; just the 48Kb of RAM and a CODE header on the front.
.SEM Snapshots used by ZX Spectrum-Emulator.
.SIT Snapshots used by Sinclair.
.SLT Super level loader snapshot. Used by many emulators these days; basically a v2/3 .Z80 snapshot with level data appended.
.SNA or .snap or .snapshot Mirage Microdrive snapshot format, used by most emulators.
.SNA 128Kb version of SNA. Distinguished by file size of 131103 bytes instead of 49179 bytes for 48Kb version.
.SNX Extended version of .SNA, used by Speccy on the Atari ST.
.SP Snapshots used by Spectrum and its earlier version, VgaSpec.
.Z80 Snapshots used by Z80 and many other emulators. Three versions in existence, the latest of which (v3/SLT) is not supported by all emulators. Very flexible; support for SamRam, 128K snapshots, etc.
.ZX Snapshots used by KGB.
.ZXS Snapshot format used by zx32; .ZXS 'snapshots' can also contain tape and disk images, but are unrelated to the .ZXS tape format.
.ZX82 Snapshots used by Speculator '97.

For the purposes of these descriptions, the following definitions apply:

byte = byte-sized variable; word = 2 bytes, long = 4 bytes. All stored in little-endian (Intel) format unless otherwise stated.

.SLT (Super Level loader Trap used by x128, WSpecEm, Z80 & others)

The level loader trap has one annoying disadvantage; lots of extra files lying around for each game. The super level loader was thought up (by Damien Burke) to replace this multi-file format with a single snapshot file containing all the level data files. It has been designed in co-operation with James McKay (x128), Gerton Lunter (Z80), Rui Ribeiro (WSpecEm) and Darren Salt (helping with Z80Em), so is well-supported already. The format was designed with future expansion in mind, as you will see.

            Size   Description
   ------------------------------------------------------------------------
            varies bytes  Z80 snapshot (version 2+)
            3      bytes  Three null bytes (compatibility; see below)
            3      bytes  "SLT" (signature)
   ---- the following blocks make up a table to access the data files -----
            2      word   data type (0 = end of table, 1 = level data)
            2      word   data identifier (for type 1 this is level number)
            4      long   data length
            2      word   data type (0 = end of table, 1 = level data)
            2      word   data identifier (for type 1 this is level number)
            4      long   data length
            ... and so on
   ---- the following blocks are the data files themselves ----------------
            varies bytes data
            varies bytes data
            ... and so on
   ------------------------------------------------------------------------

The three null bytes after the end of the snapshot are for compatibility reasons; older versions of Z80 would crash if the extra data was just appended to the snapshot. With these three null bytes, they just complain about an error in the snapshot file instead. This, of course, presumes you have renamed the .SLT file to .Z80 and attempted to load it into an older emulator!

After the "SLT" signature, there is a table of data types and sizes. Only data types 0 (end of table) and 1 (level data) are supported at the moment, so if other values are encountered an emulator should ignore that data block.

To read a level data file using .SLT, the emulator should find the correct entry in the table (type = 1, identifier matching the A register when the ED/FB instruction was encountered), get its size from the table and calculate its position from the total of sizes of data blocks previous to the required one, added to the position of the end of the table. E.g., to load level 2 from a .SLT snapshot with this table:

   Position  Size  Value  Description
   ------------------------------------------------------------------------
   40000     2     1      data type = level data
   40002     2     1      data identifier = level 1
   40004     4     256    data length = 256 bytes
   40008     2     1      data type = level data
   40010     2     2      data identifier = level 2
   40012     4     128    data length = 128 bytes
   40016     2     0      data type = end of table
   40018     2     *      data identifier = unused (may as well be zero)
   40020     4     *      data length =  unused (may as well be zero)
   40024     256   *      data block for level 1
   40280     128   *      data block for level 2
   ------------------------------------------------------------------------
   (* = could be anything)

So, the size of level 2 is 128 bytes, and its located at the end of the table (40024) + the length of all previous blocks (just 256 here) = 40280.

Level data is packed in the same way as Z80 snapshot memory banks are.

The trainspotter award seekers of you may wonder why a whole word is used for the data identifier; after all, this is the level number and is held in the A register, so could be just a byte. For level data, correct. But future expansion is better served by a word. For the same reasons, the data length is held as a long word instead of just a word; level data will never exceed 64Kb (indeed, could not even be as much as 48Kb), but future data types may do so. One example; embedding a scan of a game's inlay card in the file is possible, and that file could exceed 64Kb easily.

See this page for Damien Burke's proposals for future data types for inclusion in .SLT snapshots.

.SNA, .snap or .snapshot (Mirage Microdrive format used by many emulators)

This format is the most well-supported of all snapshot formats (though Z80 is close on its heels) but has a drawback:

As the program counter is pushed onto the stack so that a RETN instruction can restart the program, 2 bytes of memory are overwritten. This will usually not matter; the game (or whatever) will have stack space that can be used for this. However, if this space is all in use when the snap is made, memory below the stack space will be corrupted. According to Rui Ribeiro, the effects of this can sometimes be avoided by replacing the corrupted bytes with zeros; e.g. take the PC from the, stack pointer, replace that word with 0000 and then increment SP. This worked with snapshots of Batman, Bounder and others which had been saved at critical points. Theoretically, this problem could cause a complete crash on a real Spectrum if the stack pointer happened to be at address 16384; the push would try and write to the ROM. How different emulators handle this is not something I know...

When the registers have been loaded, a RETN command is required to start the program. IFF2 is short for interrupt flip-flop 2, and for all practical purposes is the interrupt-enabled flag. Set means enabled.

   Offset   Size   Description
   ------------------------------------------------------------------------
   0        1      byte   I
   1        8      word   HL',DE',BC',AF'
   9        10     word   HL,DE,BC,IY,IX
   19       1      byte   Interrupt (bit 2 contains IFF2, 1=EI/0=DI)
   20       1      byte   R
   21       4      words  AF,SP
   25       1      byte   IntMode (0=IM0/1=IM1/2=IM2)
   26       1      byte   BorderColor (0..7, not used by Spectrum 1.7)
   27       49152  bytes  RAM dump 16384..65535
   ------------------------------------------------------------------------
   Total: 49179 bytes
.SNA (128Kb version) (SP_EMU)

This is simply the SNA format extended to include the extra memory banks of the 128K/+2 machines, and fixes the problem with the PC being pushed onto the stack - now it is located in an extra variable in the file (and is not pushed onto the stack at all). The first 49179 bytes of the snapshot are otherwise exactly as described above, so the full description is:

   Offset   Size   Description
   ------------------------------------------------------------------------
   0        27     bytes  SNA header (see above)
   27       16Kb   bytes  RAM bank 5 \
   16411    16Kb   bytes  RAM bank 2  } - as standard 48Kb SNA file
   32795    16Kb   bytes  RAM bank n / (currently paged bank)
   49179    2      word   PC
   49181    1      byte   port 7FFD setting
   49182    1      byte   TR-DOS rom paged (1) or not (0)
   49183    16Kb   bytes  remaining RAM banks in ascending order
   ...
   ------------------------------------------------------------------------
   Total: 131103 or 147487 bytes

The third RAM bank saved is always the one currently paged, even if this is page 5 or 2 - in this case, the bank is actually included twice. The remaining RAM banks are saved in ascending order - e.g. if RAM bank 4 is paged in, the snapshot is made up of banks 5, 2 and 4 to start with, and banks 0, 1, 3, 6 and 7 afterwards. If RAM bank 5 is paged in, the snapshot is made up of banks 5, 2 and 5 again, followed by banks 0, 1, 3, 4, 6 and 7.

.SP (Spectrum)
   Offset   Size   Description
   ------------------------------------------------------------------------
   0        2      byte   "SP" (signature)
   2        2      word   Program length in bytes (normally 49152 for 48K
                          snaps, or 16384 for 16K snaps)
   4        2      word   Program location (normally 16384)
   6        8      word   BC,DE,HL,AF
   14       4      word   IX,IY
   18       8      word   BC',DE',HL',AF'
   26       2      byte   R,I
   28       4      word   SP,PC
   32       2      word   0 (reserved for future use)
   34       1      byte   Border color
   35       1      byte   0 (reserved for future use)
   36       2      word   Status word
   ------------------------------------------------------------------------

   Status word:
   Bit     Description
   ------------------------------------------------------------------------
   15-8    Reserved for future use
    7-6    Reserved for internal use (0)
      5    Flash: 0=INK/1=PAPER
      4    Interrupt pending for execution
      3    If 1, IM 0; if 0, bit 1 determines interrupt mode
           (Spectrum v 0.99e had this behaviour reversed, and this
           bit was not used in versions previous to v 0.99e)
      2    IFF2 (internal use)
      1    Interrupt Mode (if bit 3 reset): 0=>IM1, 1=>IM2
      0    IFF1: 0=DI/1=EI
.Z80 (Z80) [from Z80 documentation]

The old .Z80 snapshot format (for version 1.45 and below) looks like this:

        Offset  Length  Description
        ---------------------------
        0       1       A register
        1       1       F register
        2       2       BC register pair (LSB, i.e. C, first)
        4       2       HL register pair
        6       2       Program counter
        8       2       Stack pointer
        10      1       Interrupt register
        11      1       Refresh register (Bit 7 is not significant!)
        12      1       Bit 0  : Bit 7 of the R-register
                        Bit 1-3: Border colour
                        Bit 4  : 1=Basic SamRom switched in
                        Bit 5  : 1=Block of data is compressed
                        Bit 6-7: No meaning
        13      2       DE register pair
        15      2       BC' register pair
        17      2       DE' register pair
        19      2       HL' register pair
        21      1       A' register
        22      1       F' register
        23      2       IY register (Again LSB first)
        25      2       IX register
        27      1       Interrupt flipflop, 0=DI, otherwise EI
        28      1       IFF2 (not particularly important...)
        29      1       Bit 0-1: Interrupt mode (0, 1 or 2)
                        Bit 2  : 1=Issue 2 emulation
                        Bit 3  : 1=Double interrupt frequency
                        Bit 4-5: 1=High video synchronisation
                                 3=Low video synchronisation
                                 0,2=Normal
                        Bit 6-7: 0=Cursor/Protek/AGF joystick
                                 1=Kempston joystick
                                 2=Sinclair 2 Left joystick (or user
                                   defined, for version 3 .Z80 files)
                                 3=Sinclair 2 Right joystick

Because of compatibility, if byte 12 is 255, it has to be regarded as being 1. After this header block of 30 bytes the 48K bytes of Spectrum memory follows in a compressed format (if bit 5 of byte 12 is one). The compression method is very simple: it replaces repetitions of at least five equal bytes by a four-byte code ED ED xx yy, which stands for "byte yy repeated xx times". Only sequences of length at least 5 are coded. The exception is sequences consisting of ED's; if they are encountered, even two ED's are encoded into ED ED 02 ED. Finally, every byte directly following a single ED is not taken into a block, for example ED 6*00 is not encoded into ED ED ED 06 00 but into ED 00 ED ED 05 00. The block is terminated by an end marker, 00 ED ED 00.

That's the format of .Z80 files as used by versions up to 1.45. Starting from version 2.0, a different format is used, since from then on also 128K snapshots had to be supported. This new format is used for all snapshots, either 48K or 128K.

Version 2.01 and 3.0 .Z80 files start with the same 30 byte header as old .Z80 files used. Bit 4 and 5 of the flag byte have no meaning anymore, and the program counter (byte 6 and 7) are zero to signal a version 2.01 or version 3.0 snapshot file.

After the first 30 bytes, the additional header follows:

        Offset  Length  Description
        ---------------------------
      * 30      2       Length of additional header block (see below)
      * 32      2       Program counter
      * 34      1       Hardware mode (see below)
      * 35      1       If in SamRam mode, bitwise state of 74ls259.
                        For example, bit 6=1 after an OUT 31,13 (=2*6+1)
                        If in 128 mode, contains last OUT to 7ffd
      * 36      1       Contains 0FF if Interface I rom paged
      * 37      1       Bit 0: 1 if R register emulation on
                        Bit 1: 1 if LDIR emulation on
      * 38      1       Last OUT to fffd (soundchip register number)
      * 39      16      Contents of the sound chip registers
        55      2       Low T state counter
        57      1       Hi T state counter
        58      1       Flag byte used by Spectator (QL spec. emulator)
                        Ignored by Z80 when loading, zero when saving
        59      1       0FF if MGT Rom paged
        60      1       0FF if Multiface Rom paged. Should always be 0.
        61      1       0FF if 0-8191 is ROM, 0 if RAM
        62      1       0FF if 8192-16383 is ROM, 0 if RAM
        63      10      5x keyboard mappings for user defined joystick
        73      10      5x ascii word: keys corresponding to mappings above
        83      1       MGT type: 0=Disciple+Epson,1=Disciple+HP,16=Plus D
        84      1       Disciple inhibit button status: 0=out, 0ff=in
        85      1       Disciple inhibit flag: 0=rom pageable, 0ff=not

The value of the word at position 30 is 23 for version 2.01 files, and 54 for version 3.0 files. The starred fields are the ones that constitute the version 2.01 header, and their interpretation has remained unchanged except for byte 34:

        Value:          Meaning in v2.01        Meaning in v3.0x
        --------------------------------------------------------
        0               48k                     48k
        1               48k + If.1              48k + If.1
        2               SamRam                  SamRam
        3               128k                    48k + M.G.T.
        4               128k + If.1             128k
        5               -                       128k + If.1
        6               -                       128k + M.G.T.

The documenation for versions 3.00 to 3.02 of Z80 had the entries for 'SamRam' and '48k + M.G.T.' in the second column of the above table reversed; also bytes 61 and 62 of the format were wrong up to version 3.04. (The snaps produced by the older versions of Z80 still follow what is above; the documentation for the older versions is wrong).

The hi T state counter counts up modulo 4. Just after the ULA generates its once-in-every-20-ms interrupt, it is 3, and is increased by one every 5 emulated milliseconds. In these 1/200s intervals, the low T state counter counts down from 17471 to 0 (17726 in 128K modes), which make a total of 69888 (70908) T states per frame.

The 5 ASCII words (high byte always 0) at 73-82 are the keys corresponding to the joystick directions left, right, down (!), up (!), fire respectively. Shift, Symbol Shift, Enter and Space are denoted by [,],/,\ respectively. The ascii values are used only to display the joystick keys; the information in the 5 keyboard mapping words determine which key is actually pressed (and should correspond to the ascii values). The low byte is in the range 0-7 and determines the keyboard row. The high byte is a mask byte and determines the column. Enter for example is stored as 0x0106 (row 6 and column 1) and 'g' as 0x1001 (row 1 and column 4).

Byte 60 must be zero, because the contents of the Multiface RAM is not saved in the snapshot file. If the Multiface was paged when the snapshot was saved, the emulated program will most probably crash when loaded back.

Bytes 61 and 62 are a function of the other flags, such as byte 34, 59, 60 and 83.

Hereafter a number of memory blocks follow, each containing the compressed data of a 16K block. The compression is according to the old scheme, except for the end-marker, which is now absent. The structure of a memory block is:

        Byte    Length  Description
        ---------------------------
        0       2       Length of compressed data (without this 3-byte header)
                        If length=0xffff, data is 16384 bytes long and not compressed
        2       1       Page number of block
        3       [0]     Data

The pages are numbered, depending on the hardware mode, in the following way:

        Page    In '48 mode     In '128 mode    In SamRam mode
        ------------------------------------------------------
         0      48K rom         rom (basic)     48K rom
         1      Interface I, Disciple or Plus D rom, according to setting
         2      -               rom (reset)     samram rom (basic)
         3      -               page 0          samram rom (monitor,..)
         4      8000-bfff       page 1          Normal 8000-bfff
         5      c000-ffff       page 2          Normal c000-ffff
         6      -               page 3          Shadow 8000-bfff
         7      -               page 4          Shadow c000-ffff
         8      4000-7fff       page 5          4000-7fff
         9      -               page 6          -
        10      -               page 7          -
        11      Multiface rom   Multiface rom   -

In 48K mode, pages 4,5 and 8 are saved. In SamRam mode, pages 4 to 8 are saved. In '128 mode, all pages from 3 to 10 are saved. There is no end marker.

Warajevo writes v2 .Z80 files, but with some extensions to deal with its Timex 2068 emulation:

xzx has also made various extensions to the .Z80 format:

.ZX (KGB) [Contributed by Troels Norgaard]

All values stored in big-endian format; on 680x0 the most significant byte goes first.

   Offset   Size   Description
   ------------------------------------------------------------------------
   0        49284  bytes  RAM dump 16252..65535
   49284    132    bytes  unused, make 0
   49416    10     word   10,10,4,1,1 (different settings)
   49426    1      byte   InterruptStatus (0=DI/1=EI)
   49427    2      byte   0,3
   49429    1      byte   ColorMode (0=BW/1=Color)
   49430    4      long   0
   49434    16     word   BC,BC',DE,DE',HL,HL',IX,IY
   49450    2      byte   I,R
   49452    2      word   0
   49454    8      byte   0,A',0,A,0,F',0,F
   49462    8      word   0,PC,0,SP
   49470    2      word   SoundMode (0=Simple/1=Pitch/2=RomOnly)
   49472    2      word   HaltMode  (0=NoHalt/1=Halt)
   49474    2      word   IntMode   (-1=IM0/0=IM1/1=IM2)
   49476    10     bytes  unused, make 0
   ------------------------------------------------------------------------
   Total: 49486 bytes
.ZX82 (Speculator '97) [Taken from the Speculator documentation]

Amiga Speculator has its own file format which I have called ZX82 format because it contains a file identifier in the first four bytes consisting of the ASCII characters "ZX82". The format has a 12 byte header which contains the normal Spectrum type file information like length, type, start etc. as well as a compression flag which is set if the file is byte run compressed. Snapshot files have a further 32 bytes of register values and border colour information. Listed below are the offset definitions taken from the Speculator source code in case you need to write a conversion utility. All registers and other values are in Motorola format (High, Low). I have defined everything in bytes to avoid any possible confusion.

* The Standard ZX82 Header
ZX_ID           rs.l    1       Identifier for a Speculator file "ZX82"
ZX_Type         rs.b    1       0:BASIC 1:Numeric 2:String 3:Code 4:Snapshot
ZX_Comp         rs.b    1       Is data block byte run compressed ? $00=No $FF=Yes
ZX_Length_H     rs.b    1       File length up to 64k (ELINE-PROG for BASIC)
ZX_Length_L     rs.b    1
ZX_Start_H      rs.b    1       Start address for code (AUTOSTART for BASIC)
ZX_Start_L      rs.b    1
ZX_ProgLen_H    rs.b    1       Array name (VARS-PROG for BASIC)
ZX_ProgLen_L    rs.b    1
ZX_ZXHdrLen     rs.b    0       Length of ZX file header
ZX_ZXData       rs.b    0       Start of Data block for standard ZX file

* The extended Snapshot ZX82 Header
ZX_Border       rs.b    1       Border colour
ZX_IntMode      rs.b    1       IntMode over-ride (0=use i_reg, 1=im1 and 2=im2)
ZX_Registers    rs.b    0       Z80 register values for Snapshot Files
ZX_iy_H_reg     rs.b    1       (High then Low i.e. Motorola format)
ZX_iy_L_reg     rs.b    1
ZX_ix_H_reg     rs.b    1
ZX_ix_L_reg     rs.b    1
ZX_de_H_reg     rs.b    1
ZX_de_L_reg     rs.b    1
ZX_bc_H_reg     rs.b    1
ZX_bc_L_reg     rs.b    1
ZX_hl_H_reg     rs.b    1
ZX_hl_L_reg     rs.b    1
ZX_af_H_reg     rs.b    1
ZX_af_L_reg     rs.b    1
ZX_de_H_alt     rs.b    1
ZX_de_L_alt     rs.b    1
ZX_bc_H_alt     rs.b    1
ZX_bc_L_alt     rs.b    1
ZX_hl_H_alt     rs.b    1
ZX_hl_L_alt     rs.b    1
ZX_af_H_alt     rs.b    1
ZX_af_L_alt     rs.b    1
ZX_sp_H_reg     rs.b    1
ZX_sp_L_reg     rs.b    1
ZX_if_H_reg     rs.b    1
ZX_if_L_reg     rs.b    1
ZX_rf_H_reg     rs.b    1
ZX_rf_L_reg     rs.b    1
ZX_pc_H_reg     rs.b    1
ZX_pc_L_reg     rs.b    1
ZX_SnpHdrLen    rs.b    0       Length of Snapshot file header
ZX_SnpData      rs.b    65496   Start of data block for Snapshot type
file

The ZX_Type field is derived from the MGT disciple directory MGT_Type-1, so further file types may be supported in this way in the future.

The compression used is the standard byte run compression as used by ILBM IFF files. The whole 48k data block is compressed as if it were one long row. See Amiga ROM Kernel Reference Manual: Devices Third Edition, Appendix A - IFF Specification (P347), Appendix C - Example Packer C code (P538).

.ZXS (zx32)

The latest specification for .ZXS files can be found on the zx32 Home Page. Note that there is also a .ZXS tape format (see below), but this is completely unrelated to this format.

Tape Files
.BLK Tape format used by Sinclair; identical to Z80's .TAP files.
.SPC Tape format used by the Polish emulator.
.ITM Format apparently used by Intermega on the MSX.
.PAN Supplementary file used by the .ITM format.
.TAP Tape format used by Z80 and many others.
.TAP Tape format used by Warajevo.
.TZX New tape format used to store turbo-loaders, etc.
.VOC Straight sound sample of a tape; used by several emulators.
.ZXS Very flexible tape format, not actually used by any emulators - used to store real Spectrum tapes in a digital format. All come from the ZX Spectrum Software Museum.

.ITM and .PAN (Used by Intermega on the MSX)

The format starts with a two byte header; the first byte specifies the number of tape blocks in this file, and the second specifies which block has some data contained in the supplementary .PAN file. (This byte is zero if there is no data in the .PAN file).

A sequence of tape blocks then follows; each block has a four byte header. The first byte of the header is the LSB of the length of the block, excluding the four byte header), the second byte is the MSB of the length, the third byte is unknown (the high nibble is always 0110), and the fourth byte is the block number (the first block is number 1). The data then follows; this is exactly as would be produced by the Speccy's ROM routine, apart from the fact that there is no checksum byte at the end.

For the block which is marked in the second byte of the file as having data in the .PAN file, the actual block length is 12295 (0x3007) bytes longer than specified in the .ITM file. The final 12295 bytes of the data block are stored as the first 12295 bytes of the .PAN file.

Finally, note that both the .ITM and .PAN files have apparently random bytes at the end. A converter for converting .ITM/.PAN files to Z80's .TAP format is available here.

.TAP/.BLK (Z80, Sinclair & many others) [from Z80 documentation]

The .TAP files contain blocks of tape-saved data. All blocks start with two bytes specifying how many bytes will follow (not counting the two length bytes). Then raw tape data follows, including the flag and checksum bytes. The checksum is the bitwise XOR of all bytes including the flag byte. For example, when you execute the line SAVE "ROM" CODE 0,2 this will result:

             |------ Spectrum-generated data -------|       |---------|

       13 00 00 03 52 4f 4d 7x20 02 00 00 00 00 80 f1 04 00 ff f3 af a3

       ^^^^^...... first block is 19 bytes (17 bytes+flag+checksum)
             ^^... flag byte (A reg, 00 for headers, ff for data blocks)
                ^^ first byte of header, indicating a code block

       file name ..^^^^^^^^^^^^^
       header info ..............^^^^^^^^^^^^^^^^^
       checksum of header .........................^^
       length of second block ........................^^^^^
       flag byte ............................................^^
       first two bytes of rom .................................^^^^^
       checksum (checkbittoggle would be a better name!).............^^

Note that it is possible to join .TAP files by simply stringing them together, for example COPY /B FILE1.TAP + FILE2.TAP ALL.TAP

For completeness, I'll include the structure of a tape header. A header always consists of 17 bytes:

        Byte    Length  Description
        ---------------------------
        0       1       Type (0,1,2 or 3)
        1       10      Filename (padded with blanks)
        11      2       Length of data block
        13      2       Parameter 1
        15      2       Parameter 2

The type is 0,1,2 or 3 for a Program, Number array, Character array or Code file. A SCREEN$ file is regarded as a Code file with start address 16384 and length 6912 decimal. If the file is a Program file, parameter 1 holds the autostart line number (or a number >=32768 if no LINE parameter was given) and parameter 2 holds the start of the variable area relative to the start of the program. If it's a Code file, parameter 1 holds the start of the code block when saved, and parameter 2 holds 32768. For data files finally, the byte at position 14 decimal holds the variable name.

.TAP (Warajevo) [from Samir Ribic]

Warajevo's tape files (TAP) has the format as follows:

At the beginning of the file there are four bytes with the pointer to the first block. Then follow four bytes with pointer to the last block. The next four bytes contain #FFFFFFFF. So, empty tape has a format:

   #04 #00 #00 #00 #00 #00 #00 #00 #FF #FF #FF #FF

Sequence #00 #00 #00 #00 #FF #FF #FF #FF is, in fact, a EOF (end of file) marker. Every block contains following:

If the block size is 65534, it is a block which contains tone record samples. The structure is:

If bytes 9, 10, 11 and 12 into a TAP file are not equal to #FF, this is TAP file which is not in native Warajevo TAP format. In this case, Warajevo assumes Z80's .TAP format.

If the block size is 65535, it is a compressed block. It looks like:

Signatures are important for the imploding algorithm used by Warajevo. This algorithm, when decompressing, copies bytes from the source file, or returns for a few bytes, and copies some bytes from a destination file.

The explaination of compressed data bytes is rather complex. We used format similar to those in PKLITE, but unlike PKLITE where signature bytes are mixed with data bytes, authors divided them in two parts, for easier debugging.

Remember elements of Imploding (LZ77) algorithm. It depends on copying of some byte sequences. For example:

   3D 18 2E 42 3D 18 2E 15 42 3D 19

will be encoded as:

   3D 18 2E 42 <Return for 4 bytes and copy 3 bytes>
   15 <Return for 5,copy 2> 19

The archivers differs on way of encoding of this special 'Return for...' code.

In Warajevo compressed format, there are two parts: signatures and data. In our example coding of signatures will be (binary):

   00001001 010100xx

while data bytes will be

   3D 18 2E 42 04 15 05 19

The signatures are finite automat that describe what to do with data bytes. If the bit is 0, this is simple data byte, if the bit is 1 this is code for returning.

In our example, four zeros in signatures means that four bytes can be simply copied (3D, 18, 2E, 42) to output buffer. The next bit is 1. This means: Return for xxxx bytes and copy yyyy.

The value of yyyy (size of string to be copied) is in signatures if less than 10 or in signatures and data bytes if greater of equal 10.

The size depends on next 2-4 signature bits:

    010: size=2
     00: size=3
    100: size=4
    101: size=5
    011: size>=10
   1100: size=6
   1101: size=7
   1110: size=8
   1111: size=9

If size is greater or equal than 10, the next data byte contains actual size-10. That means: maximal string size is 265.

The next data byte determine lower byte of distance of string to be copied (lower byte of xxxx). If size=2, higher bit is always zero (so for this size distance can be maximally 255). If size differs from 2 the next 1-6 signature bits determine higher byte:

        1: higher byte=0
     0000: higher byte=1
     0001: higher byte=2
    00100: higher byte=3
    00101: higher byte=4
    00110: higher byte=5
    00111: higher byte=6
   01nnnn: higher byte=7+nnnn

Experiment with some ASCII text compressed. There is algorithm in Pascal for decompressing to understand the format:

procedure decompress_b;
label
  lb,b0,b1,b11,b01,b10,b110,b111,b010,b00,b100,b101,b011,b1100,
  b1101,b1110,b1111,v,v0,v1,v00,v01,v000,v001,v0000,v0001,v00100,v00101,
  v00110,v00111,v0010,v0011,izlaz;

var
  b,put:byte;
  bytes,return_for,i,auxilary:word;
  finished:Boolean;
begin
  OutputBufEnd:=0;
  CurrPosInputBuffer:=SignatureSize+1;
  CurrentSignaturePosition:=0;
  CurrentSignature:=InputBuffer^[CurrentSignaturePosition];
  BitCounter:=0;
  if duzina_ul_dek=0 then finished:=true else finished:=false;
  while not finished do begin
    if nextbit=0 then begin
      TakeFromInputBuffer(b,finished);
      PutToOutputBuffer(b);
    end
     else begin
       I know, it is  goto, but more readable than
        nested if then else sequences
        lb: if nextbit=0 then goto b0 else goto b1;
        b0: if nextbit=0 then goto b00 else goto b01;
        b1: if nextbit=0 then goto b10 else goto b11;
        b11: if nextbit=0 then goto b110 else goto b111;
        b01: if nextbit=0 then goto b010 else goto b011;
        b10: if nextbit=0 then goto b100 else goto b101;
        b110: if nextbit=0 then goto b1100 else goto b1101;
        b111: if nextbit=0 then goto b1110 else goto b1111;
        b010: bytes:=2;
          TakeFromInputBuffer(b,finished);
          return_for:=b;
          goto izlaz;
        b00: bytes:=3;goto v;
        b100: bytes:=4;goto v;
        b101: bytes:=5;goto v;
        b011: TakeFromInputBuffer(b,finished);
          bytes:=b+10;goto v;
        b1100: bytes:=6;goto v;
        b1101: bytes:=7;goto v;
        b1110: bytes:=8;goto v;
        b1111: bytes:=9;goto v;
        v: TakeFromInputBuffer(b,finished);
        return_for:=b;
        if nextbit=0 then goto v0 else goto v1;
        v0: if nextbit=0 then goto v00 else goto v01;
        v1:goto izlaz;
        v00: if nextbit=0 then goto v000 else goto v001;
        v01: Auxsilary:=7;
          if nextbit=1 then Auxsilary:=Auxsilary+8;
          if nextbit=1 then Auxsilary:=Auxsilary+4;
          if nextbit=1 then Auxsilary:=Auxsilary+2;
          if nextbit=1 then Auxsilary:=Auxsilary+1;
          return_for:=return_for+256*Auxsilary;
          goto izlaz;
        v000: if nextbit=0 then goto v0000 else goto v0001;
        v001: if nextbit=0 then goto v0010 else goto v0011;
        v0010: if nextbit=0 then goto v00100 else goto v00101;
        v0011: if nextbit=0 then goto v00110 else goto v00111;
        v0000: return_for:=return_for+1*256;goto izlaz;
        v0001: return_for:=return_for+2*256;goto izlaz;
        v00100: return_for:=return_for+3*256;goto izlaz;
        v00101: return_for:=return_for+4*256;goto izlaz;
        v00110: return_for:=return_for+5*256;goto izlaz;
        v00111: return_for:=return_for+6*256;goto izlaz;
        izlaz:
        for i:=1 to bytes do begin
          put:=OutputBuffer^[OutputBufEnd-return_for+1];
          PutToOutputBuffer(put)
        end;
     end else
  end while
end; decompress_b

Complex? Yes it is. I spent more than 30 days in developing algorythm, analysing of some archivers, optimizing compression speed (it is still slow, but acceptable) , and I worked mostly on paper, because it was in hardest days of summer 1993, without electric power, water and food (in this time I losed 1kg weekly), when only miracle saved Sarajevo of fall. In this time I had not leave the army building, and while I waited for a new battle tasks I developed the compression algorythm.

.TZX (x128, xzx v2 & others)

.TZX files are a format developed by Tomaz Kac to allow the storage of games with non-standard loaders in a format much smaller than .VOC files. The full specification can be found at World of Spectrum.

Disk Files

.DSK Generic disk image format, used for +3 disks by x128, xzx and others.
.FDI Image of a TR-DOS disk, used by UKV Spectrum Debugger.
.$? Hobeta image of a TR-DOS file; used by xzx
.IMG Image of a Disciple/+D disk, used by x128
.MGT Image of a Disciple/+D disk, used by x128
.SCL Image of a collection of TR-DOS files, used by xzx.
.TRD Image of a TR-DOS disk, used by x128, xzx and others.

.DSK (x128, xzx v2 & others)

See the specification at Kevin Thacker's Unofficial Amstrad WWW Resource (.DSK files were originally used on some of the Amstrad CPC emulators).

.FDI (UKV Spectrum Debugger)

[Translated from UKV Spectrum Debugger's documentation by Mac Buster]

   Offset   Field size    Description  

    0x00       0x03       Text "FDI"
    0x03       0x01       Write protection (0: write enabled; 1: disabled)
    0x04       0x02       Number of cylinders
    0x06       0x02       Number of heads
    0x08       0x02       Offset of disk description
    0x0A       0x02       Data offset
    0x0C       0x02       Length of additional information in header. (UKV
                          uses 00)
    0x0E       (x)        Additional information; length is specified in the
                          previous field.
    0x0E+(x)              Track headers area. This section contains all
                          information on the disk format. This area must
                          contain at least "Number of cylinders"*"Number of
                          heads" headers. The headers are stored in the
                          sequence Cyl 0 Head 0; Cyl 0 Head 1; Cyl 1 Head 0
                          etc.
   (Description offset)   A description of the disk terminated with 0x00 can
                          be placed here; the MAKEFDI utility (supplied by
                          UKV) allows for up to 64 characters, including
                          the terminating null.
   (Data offset)          The actual disk data. The size and sequence depends
                          on the disk format.

Track header format

   Offset   Field size    Description

    0x00       0x04       Track offset: the offset of the track data, relative
                          to the data offset defined above.
    0x04       0x02       (Always 0x0000)
    0x06       0x01       Number of sectors on this track.
    0x07   (Sectors*7)    Sector infomation:
                          Bytes 00-03 give the cylinder number, head number,
			  sector size (00: 128 bytes; 01: 256; 02: 512; 03:
                          1024; 04: 4096) and sector number respectively.
                          Byte 04 contains the flags:
   		            Bits 0-5 are CRC marks: if the CRC was correct for
   			    a sector size 128,256,512,1024 or 4096, then the
			    respective bit will be set. If all bits are 0 then
                            there was a CRC error when this sector was
                            written.
		            Bit 6 is always 0.
		            Bit 7 is 0 for normal data, or 1 for deleted data.
		          Bytes 05-06 give the sector offset, relative to
		          (data offset+track offset)			 
   7*(Sectors+1)          Track header length

Note that UKV 1.2 does not use the flag byte.

Hobeta

[From Mac Buster]

Hobeta files (which use the extension .$?) is simply an image of a TR-DOS file, rather than a complete disk; it is just the file with a 17-byte header:

  Offset      Name       Size       Description

   0x00     FileName     0x08      TR-DOS file name
   0x08     FileType     0x01      TR-DOS file type
   0x09     StartAdr     0x02      start address of file
   0x0A     FlLength     0x02      length of file (in bytes)
   0x0C     FileSize     0x02      size of file (in sectors) 
   0x0E     HdrCRC16     0x02      Control checksum of the 15 byte
                                   header (not sector data!)
.IMG (x128)

This is just a simple dump of a Disciple/+D disk, in the order:

.MGT (x128)

Again, this is just a simple dump of a Disciple/+D disk, but in the order:

.SCL

[From Mac Buster]

The first 8 bytes of the file is the ASCII string "SINCLAIR"; the 9th byte is the number of TR-Dos files contained in the file. There then follows a 14 byte long descriptor for each file in archive:

     8 bytes - file name
     1 byte  - file type
     2 bytes - start address
     2 bytes - file length in bytes
     1 byte  - file size in sectors (each sector is 256 bytes)

After all the descriptors follows the sector data and after that a 4 bytes long simple sum (not a checksum!) of all the previous bytes in the file. Please note that a TR-Dos file cannot be longer that 255 sectors; each sector is 256 bytes long, so maximum file size is be 65280 bytes.

.TRD (x128, xzx v2 & others)

See the TR-DOS System Info from Ramsoft.

Other Files

.AZX New format designed for storing sound from Spectrum programs.
.DAT Data files used by level-loader versions of a game (Z80Em does not use a .DAT extension at all; instead files are just numbered, e.g. "1" instead of "GAME1.DAT").
.DCK Used by Warajevo for Timex memory expansions.
.MDR Microdrive cartridge file as used by Z80 and xzx v2 amongst others.
.NET Used by Warajevo for the Interface I Network.
.OUT OUT logs from Z80.
.POK Poke files used by the Spectrum Games Database.
.SCR Screendumps from Z80, WSpecEm and others.

.AZX (none yet)

AZX files are a new format devised by Mac Buster for storing sound output from Spectrum programs. The specification can be found at World of Spectrum.

.DCK (Warajevo)

DCK files keeps information about memory content of various Timex memory expansions, and information which chunks of extra memory are RAM chunks and which chunks are ROM chunks. Such files have relatively simple format. At the beginning of a DCK file, a nine-byte header is located. First byte is the bank ID which has the following meaning:

   0:     DOCK bank (the most frequent variant)
   1-253: Reserved for expansions which allow more than three 64 Kb
          banks (currently not implemented)
   254:   EXROM bank (using this ID you may insert RAM or ROM chunks
          into EXROM bank; such hardware exists for the real TS2068)
   255:   HOME bank (mainly useless, HOME content is typically stored in a Z80
          file); however, using this bank ID you may replace content of Timex
          HOME ROM, or turn Timex HOME ROM into RAM

This numbering of banks is in according to convention used in various routines from the TS2068 ROM. After the first byte, following eight bytes corresponds to eight 8K chunks in the bank. Organization of each byte is as follows:

   bit  D0:    0 = read-only chunk, 1 = read/write chunk
   bit  D1:    0 = memory image for corresponding chunk is not present in DCK
               file, 1 = memory image is present in DCK file
   bits D2-D7: reserved (all zeros)                                        

To be more precise, these bytes will have the following values:

After the header, a pure binary image of each chunk is stored in DCK file. That's all if only one bank is stored in DCK file. Else, after the memory image, a new 9-byte header for next bank follows, and so on.

.MDR (Z80, xzx v2, others) [from Z80 documentation]

The following information is adapted from Carlo's documentation. It can also be found in the 'Spectrum Microdrive Book', by Ian Logan (co-writer of the excellent 'Complete Spectrum ROM Disassembly').

A cartridge file contains 254 'sectors' of 543 bytes each, and a final byte flag which is non-zero is the cartridge is write protected, so the total length is 137923 bytes. On the cartridge tape, after a GAP of some time the Interface I writes 10 zeros and 2 FF bytes (the preamble), and then a fifteen byte header-block-with-checksum. After another GAP, it writes a preamble again, with a 15-byte record-descriptor-with-checksum (which has a structure very much like the header block), immediately followed by the data block of 512 bytes, and a final checksum of those 512 bytes. The preamble is used by the Interface I hardware to synchronise, and is not explicitly used by the software. The preamble is not saved to the microdrive file:

    Offset Length Name    Contents
    ------------------------------
      0      1   HDFLAG   Value 1, to indicate header block
      1      1   HDNUMB   sector number (values 254 down to 1)
      2      2            not used
      4     10   HDNAME   microdrive cartridge name (blank padded)
     14      1   HDCHK    header checksum (of first 14 bytes)

     15      1   RECFLG   - bit 0: always 0 to indicate record block
                          - bit 1: set for the EOF block
                          - bit 2: reset for a PRINT file
                          - bits 3-7: not used (value 0)
     16      1   RECNUM   data block sequence number (value starts at 0)
     17      2   RECLEN   data block length (<=512, LSB first)
     19     10   RECNAM   filename (blank padded)
     29      1   DESCHK   record descriptor checksum (of previous 14 bytes)
     30    512            data block
    542      1   DCHK     data block checksum (of all 512 bytes of data
                           block, even when not all bytes are used)
    ---------
    254 times

(Actually, this information is 'transparent' to the emulator. All it does is store 2 times 254 blocks in the .MDR file as it is OUTed, alternatingly of length 15 and 528 bytes. The emulator does check checksums, see below; the other fields are dealt with by the emulated Interface I software.)

A used record block is either an EOF block (bit 1 of RECFLG is 1) or contains 512 bytes of data (RECLEN=512, i.e. bit 1 of MSB is 1). An empty record block has a zero in bit 1 of RECFLG and also RECLEN=0. An unusable block (as determined by the FORMAT command) is an EOF block with RECLEN=0.

The three checksums are calculated by adding all the bytes together modulo 255; this will never produce a checksum of 255. Possibly, this is the value that is read by the Interface I if there's no or bad data on the tape.

In normal operation, all first-fifteen-byte blocks of each header or record block will have the right checksum. If the checksum is not right, the block will be treated as a GAP. For instance, if you type OUT 239,0 on a normal Spectrum with interface I, the microdrive motor starts running and the cartridge will be erased completely in 7 seconds. CAT 1 will respond with 'microdrive not ready'. Try it on the emulator...

Warajevo uses basically the same format, but ignores the `read-only' final byte (it obtains this information from the file attributes), and also the files do not have to contain all 254 sectors.

.NET (Warajevo)

.NET files are used by Warajevo to emulate the Interface I Network, which allowed up to 8 different Spectrums to talk to each other.

The format of the network files is very simple. They have 260 bytes (or more, but excess bytes will not be used), with following structure:

   Byte    Length  Description

     0       2     Package ID (used for fast checking whether content of the
                   Net file is changed)
     2       2     Reserved; not yet used          
     4     256     Content of the package
.PAL (Warajevo)

The WARAJEVO.PAL file is used by Warajevo to set its colour palette. They have a very simple 48-byte format: the first three bytes correspond to R, G and B value for color 0, next three bytes correspond to RGB for color 1, etc; the first 24 bytes are related to BRIGHT 0 colors, and next 24 bytes are related to BRIGHT 1. All values must be in the range 0-63.

.POK (Spectrum Games Database, Sinclair Spectrum Emulator)

[From Martijn van der Heide]

The .POK file format is a proprietary format designed for use with SGD (from version 1.20) and was originally used to POKE snapshots prior to launching an emulator to play the specific game. This mechanism works on snapshots only.

Each trainer contains one or more POKEs (sometimes a game check needs more than one poke to acquire a result). All trainers for a game are written after each other. The first character in a line of the file determines the content of the line.

'N' means: this is the Next trainer,
'Y' means: this is the last line of the file (the rest of the file is ignored).

After the 'N' follows the name/description of this specific trainer. This string may be up to 30 characters. There is no space between the 'N' and the string.

The following lines, up to the next 'N' or 'Z' hold the POKEs to be applied for this specific trainer. Again, the first character determines the content.

'M' means: this is not the last POKE (More)
'Z' means: this is the last POKE

The POKE line has the format:

   lbbb aaaaa vvv ooo

Where l determines the content, bbb is the bank, aaaaa is the address to be poked with value vvv and ooo is the original value of aaaaa. All values are decimal, and separated by one or more spaces, apart from between l and bbb; however, the bank value is never larger than 8, so you will always see 2 spaces in front of the bank.

The field bank field is built from

bit 0-2 : bank value
      3 : ignore bank (1=yes, always set for 48K games)

If the field <value> is in range 0-255, this is the value to be POKEd. If it is 256, a requester should pop up where the user can enter a value.

The 'original' field holds the original value at the address. It is used to remove a POKE. Normally, when applying a POKE, the original value can be read from the address. Sometimes however, games as found on the internet are already POKEd, so the original value can not be read. If this field is filled in (non-0) you still have the possibility to remove the trainer. (This format cannot handle the possibility that the original value was 0).

.SCR (Z80, WSpecEm, others)

These files are just Spectrum screen dumps, and are simply the 6912 bytes of pixel and attribute data found at address 16384, stored on disk in exactly the same way as they are stored in memory.

To elaborate; the Spectrum screen is split into four areas; top third, mid third, bottom third and attributes (colours). The thirds each consist of 2048 bytes and the attribute area is 768 bytes (32 characters wide x 24 lines). So the first 6144 bytes are the actual pixel data and the remainder decides what two colours are used in each 8x8 square.

Each third of the screen is laid out unusually; the first 32 bytes are the pixels for the top row of the first character line, then the next 32 bytes are the pixels for the top row of the second character line and so on until you reach the ninth load of 32 bytes, which is the second row of the first character line. Next 32 bytes is the second row of the second character line, and so on. It's hard to explain, so the best thing to do is see for yourself; write a program to POKE data to 16384 up and see how the bytes fill in on the screen.

-----

This FAQ is maintained by Philip Kendall; distribution is permitted only under the conditions specified in the copyright notice.
Primary site for this FAQ: http://www.ast.cam.ac.uk/~pak/cssfaq/index.html.