EZX snap format

(Ñ) by Vladimir Kladov, 2003

This format is intended to use it in EmuZWin 2 Spectrum emulator. It allows to save exact state of Spectrum machine, including current registers, memory and other internal data, and also tape state, inserted TR-DOS-disks (with entire content), debug environment, pokes, keyboard redirection and other necessary information.

EZX must be started with four (4) characters signature 'Emuz' (starting from version 2.4, EZX can be compressed. In such case, 'EZX' signature (3 bytes) used, and all other data are compressed using UPX algorithm, fast and extemely compact), and always should have extension 'EZX'. The first part of the file contains fixed part, representing current Spectrum machine snapshot. This part of a file should always be read (except may be a case when only a screen requested for load). It's structure (including signature) is:

TSpecData = packed Record
Signature : array[ 0..3 ] of Char; // 'Emuz'
ROM0, ROM1: TMemoryBank; // ROM0=S128 rom; ROM1=S48 rom
RAMs      : array[ 0..7 ] of TMemoryBank;
Lock7FFD  : Boolean;     // true, if S48K only
State     : TSpecState;  // registers, etc.
Sound     : TSoundChipState;  // sound chip AY state
ReleaseDescriptor: DWORD;     // not used
Tape      : TTapeData;        // current tape reader state
end;

Substructures used are defined as follows:

TMemoryBank = array[ 0..16383 ] of Byte;

TSpecState = packed Record
AF, BC, DE, HL, IX, IY,
AFalt, BCalt, DEalt, HLalt, 
PC, SP               : Word;
I, R, HiddenReg      : Byte;
IFF1, IFF2, IntSignal: Boolean;
ImMode               : Byte;
TactsFromLastInt     : DWord;
BankROM_0000,                   // 0=rom S128, 1=rom S48
				// 2=rom TR-DOS, 3=rom IF-1(8K ROM+8K RAM)
BankRAM_C000,                   // 0..7 
BankVideo            : Byte;    // 0=RAM Bank 5, 1=RAM Bank 7
BorderColor          : Byte;    // 0..7
MIC                  : Boolean; 
JustAfterEI          : Boolean; // Interrupt disable for a single instruction if TRUE
Flash                : Boolean; // TRUE if flushed
FramesFromLastFlashSwitch: Byte; // 0..15
end;

TSoundChipState = packed record
LastFFFD             : Byte;
Regs                 : array[ 0..15 ] of Byte;
end;

TTapeData = packed record
    TapeImgData: Pointer;
    TapeImgLen: Integer;
    TapePosition: Integer;
    PulseLength: Integer; // current pulse length
    TactsLeast: Integer;  // how many tacts current pulse should continue
    BitIndex: Integer;
    CurByte: Byte;
    Pilot: Integer;       // when LoadSpectrum called, 1 if to double tone except SpeedLock1 & 2
    Active: Boolean;
end;

The last structure should be ignored if following chunks certain to tape image and tape reader state are not loaded.

Other chunks always contains four-byte chunk name and its data length to allow skipping unsupported chunks.


'NAME' chunk - initial name of program loaded
This chunk is introduced in version 2.4 to store name of file 
(without extension). This name is used in Autosave.ezx file to 
restore main window caption after loading the state.

offset size   description
0      4      name         = 'NAME'
4      4      len          = name length.
8      len    name string (no trailing zero).

'RAM ' chunk - additional RAM page 16K

This chunk is used for storing additional RAM memory banks in 
some Spectrum models having more memory then 128K (Pentagon256K/512K,
Scorpion256K/1024K, etc.)

offset size   description
0      4      name         = 'RAM '
4      4      size         = size of data (16385)
8      1      Bank number (8..63)
9      16384  Bank memory

'PORT' chunk - additional control ports

This chunk is used for storing additional ports (like memory controlling ports, e.g. 1FFD for Scorpion/KAY):

offset size   description
0      4      name          = 'PORT'
4      4      size         = size of data (N ports * 3)
8      2      Port Number
9      1      Value


'GS  ' chunk - General Sound Machine State

This chunk is used for storing General Sound plate state including its Z80 processor state, ports, RAM.
ROM used is not stored, and GS.ROM must be provided in the emulator directory or \ROMS subdirectory as usual.

offset size   description
0      4      name          = 'GS  '
4      4      size         = size of data (...)
8      ...  
  GS machine state


'POKS' chunk - a list of pokes supplied:

offset size   description
0      4      name         = 'POKS'
4      4      size         = size of entire data
8      Sequence of strings (separated with #13 and #10 as usual text file)
       in .POK-file format.

'BRKS' chunk - a list of break points for the debugger:

offset size   description
0      4      name        = 'BRKS'
4      4      size        = size of entire data
8      4      N = number of TBreakPoint structures
12     ...    array of TBreakPoint structures

where TBreakPoint is defined as follows:

TPoke = packed record
  MemBank   : Byte;    // 0=ROM0, 1=ROM1, 10H..17H=RAM0..RAM7
  Addr      : Word;    // 0000H..3FFFH in a bank
  Counter   : DWORD;
  StopWhen  : Byte;
  CondCount : Byte;
  Conditions: array[1..CondCount] of array[0..31] of Char;
end;

each condition is a string of format <TARGET>[<MASKorOFFSET>]<OP><VALUE>
where <TARGET> ::= { A | B | BC | (BC) | C | D | DE | (DE) | E | F |
 H | HL | (HL) | I | IFF1 | IFF2 | IM | IX | (IX) | IY | (IY) | L |
 (Addr) | PC | (PC) | R | RAM | ROM | SP | TState }
if target is (IX) or (IY), <MASKorOFFSET> is used as an offset and
is written like (IX+XXXX) (X=hexadecimal digit). If target is (Addr),
<MASKorOFFSET> also used to indicate an addr (in form (XXXX)) Otherwise it is used as
a mask and is written like &XXXX or &XX;
      <OP> ::= { = | <> | < | <= | > | >= };
      <VALUE> always is hexadecimal byte or word written like XX or XXXX.

'LABS' chunk - a list of labels for the debugger:

offset size   description
0      4      name        = 'LABS'
4      4      size        = size of entire data
8      4      N = number of TLabelDef structures
12     ...    array of TLabelDef structures

where TLabelDef is defined as follows:

TLabelDef = packed record
  MemBank   : Byte;
  Addr      : Word;
  LabelName : array of Char; // until #00
end;

LabelName can be any ASCII.

'ASMZ' chunk - a text in assembler window:

offset size   description
0      4      name         = 'ASMZ'
4      4      size         = size of entire data
8      size   text (lines are separated with #13#10, the text is finished with #00)

'KEYS' chunk - key re-definition table.

offset size   description
0      4      name = 'KEYS'
4      4      size = size of entire data
8      Sum(i=1..N: Sizeof(TKeyMap) or Sizeof(TKeyMapOld) ) = 
	      array of key definitions

where each TKeyMap or TKeyMapOld is defined as follows:

  TKeyMapOld = packed Record
    PCKey: Byte;
    ZXKey1: DWORD;
    ZXKey2: DWORD;
    Style: TPressStyle;
    Timer: Integer; // time to press key(s) again (pressLoop style)
    Hold: Integer;  // time to hold key(s) pressed (pressAutoUp, pressLoop)
  end;
  TKeyMap = packed Record
    PCKey: Word;
    ZXKey1: DWORD;
    ZXKey2: DWORD;
    Style: TPressStyle;
    Timer: Integer; // time to press key(s) again (pressLoop style)
    Hold: Integer;  // time to hold key(s) pressed (pressAutoUp, pressLoop)
  end;
If the first byte of a record is 3A or 3B, new TKeyMap is present,
otherwise it is the TKeyMapOld (which differ by the first field length).
New TKeyMap intruduced to allow representing Joystick1 (3A) and Joystick2 (3B)
directions and keys:
Function Joystick1 Joystick2
Up 013A 013B
Down 023A 023B
Left 033A 033B
Right 043A 043B
Fire (Button1) 053A 053B
Button2 063A 063B

...

Button32 243A 243B
TPressStyle = ( pressNormal, pressFixed, pressAutoUp, pressLoop );
ZXKeyN fields contains ZX Spectrum key coded as follows:
const
     kCapsShft = $0FE; kZ     = $0FD; kX     = $0FB; kC     = $0F7; kV     = $0EF;
     kA        = $1FE; kS     = $1FD; kD     = $1FB; kF     = $1F7; kG     = $1EF;
     kQ        = $2FE; kW     = $2FD; kE     = $2FB; kR     = $2F7; kT     = $2EF;
     k1        = $3FE; k2     = $3FD; k3     = $3FB; k4     = $3F7; k5     = $3EF;
     k0        = $4FE; k9     = $4FD; k8     = $4FB; k7     = $4F7; k6     = $4EF;
     kP        = $5FE; kO     = $5FD; kI     = $5FB; kU     = $5F7; kY     = $5EF;
     kEnter    = $6FE; kL     = $6FD; kK     = $6FB; kJ     = $6F7; kH     = $6EF;
     kSpace    = $7FE; kSymShft = $7FD; kM   = $7FB; kN     = $7F7; kB     = $7EF;
     jR        = $8FE; jL     = $8FD; jD     = $8FB; jU     = $8F7; jFire  = $8EF;
     k_        = $FFFF; (no key)

'JOY ' chunk - Joysticks configuration

offset size   description
0      4      name = 'JOY '
4      4      size = size of entire data (5)
8      1      Joysticks count: 0..2
9      1      Joystick 1 assignment (0 = Kempston, 1 = SinclairI,
              2 = SinclairII, 3 = FullerBox, 4 = Cursor, 5 = Custom)
10     1      Joystick 2 assignment (should differ from the 1)
11     1      Invert Y axe for Joystick 1
12     1      Invert Y axe for Joystick 2


'AMXM' chunk - AMX Mouse unit emulation state

offset size   description
0      4      name = 'AMXM'
4      4      size = size of entire data (11)
8      1      IE Latches and PIO Modes:
            bit 0: IE Latch A;
            bit 1: IE Latch B;
            bits 2-3: PIO Mode A;
            bits 4-5: PIO Mode B;
    bit 6: Data A (0 - direction is positive, 1 -
              negative), this value read via port #1F;
    bit 7: Data B - read via port #3F;
9      1      Int Vector A
10     1      Int Vector B
11     1      Int Counter A in this frame 0..32 (used to prevent
    more then 32 ints in one frame for mice X change);
12     1      Int Counter B
13     1      Mouse X last position 0..255
14     1      Mouse Y last position 0..191
15     4      AMX_TactCounter: HiWord contains tacts left to
    handle the next AMX event. This counter is set to
    value #7FFFFFFF initially and on each normal INT;
    and to #300000 on EI instruction to allow 48 TStates
    wait period before initiating the first AMX interrupt
    in a sequence.


'AYMS' chunk - current AY Mouse Speed

offset size   description
0      4      name = 'AYMS'
4      4      size = size of entire data (1)
8      1      Speed (1 or 4)


'COLR' chunk - color adjustment table:

offset size   description
0      4      name = 'COLR'
4      Sizeof(TColorTable) - a table of colors to use it to represent screen.

TColorTable = packed record 
NormalBlack, NormalRed, NormalBlue, NormalMagenta,
NormalGreen, NormalCyan, NormalYellow, NormalWhite,
BrightBlack, BrightRed, BrightBlue, BrightMagenta,
BrightGreen, BrightCyan, BrightYellow, BrightWhite: TRGB;
end;

TRGB = packed record
  R, G, B: Byte;
end;

'LDIR' chunk - flag to allow fast LDIR/LDDR/CPIR/CPDR emulation:

offset size   description
0      4      name = 'LDIR'
4      4      size = 1 (size of entire data)
8      1      flag = 0 LDIR/LDDR/CPIR/CPDR fast emulation disabled,
                     1 enabled (default)
In EmuZWin, fast LDIR/... emulation does not affect emulation 
accuracy though, so it can be left turned on always.

'DISK' chunk - TR-DOS disk inserted:

This chunk is introduced in version 2.2 of EmuZWin, having TR-DOS support. A single EZX file can contain up to four TR-DOS disks inserted (A,B,C,D).

offset size   description
0      4      name = 'DISK'
4      4      size (size of entire disk data, for disks with standard 256-byte sectors, can be calculated as 266*(sectors count)+4+1 bytes).
8      1      Disk unit letter ('A', 'B', 'C', 'D')
9      1      Current Track #
10     1      Disk states
              D0: 1-ReadOnly; D1: 1-head down; D2: 0=FM, 1=MFM
11     1      Reserved to store other unit states
--- starting from here, content of all sectors listed excluding those
    containing nulls:
12     1      Cylinder # (0..254, though 83 usually is maximum for

              physical disk, value 255 means end of disk data and
              should be the last byte in the disk image).
13     1      Head (0-down, 1-up)

14     1      Track ID stored in the sector label (it can differ from Track # above
              and can be of any byte value.
15     1      Side # stored in the sector label (usually the same as Head above)
16     1      Sector ID (1..16 usually, but any byte value possible).
              The same track can have several sectors with the same ID.
17     1      Sector size code (0=128 bytes, 1=256 bytes, 2=512 bytes, 3=1024bytes,

              4=4096 bytes, other values can not be used, though actual data size
              is stored separately).
18     2      Control codes
20     2      Sector data length (though usually this value = 256, it can be different for non-standart formats).
22     (SectorDataLength) Actual sector data
              (usually of 256 bytes length)
--- from here, the next sector starts, ets. until Track# = FF

Other notes: order of Tracks, Sectors, Sides does not matter (though EmuZ itself stores its sorted). Also, duplicated sectors allowed (reserved for non-standard formatted disks).


'BETA' chunk - TR-DOS controller state:

This chunk is introduced in version 2.2 of EmuZWin, having TR-DOS support.

offset size   description
0      4      name = 'BETA'
4      4      size (size of entire chunk data, 9).
8      1      D1,D0: Current disk unit (0='A', 1='B', 2='C', 3='D');
              D2: Seek direction; D3: Head down;
              D5,D4: Current operation (0=no operation, 1=read, 2=write,
                     3=format - the last is not implemented,
                     just reserved)
              D6: not used, 0; D7: 1=TR-DOS ROM paged on
9      1      Operation Track# (0..254)
10     1      Operation Sector# (D7: Side; D6-D0: Sector# 0..127)
11     1      Sectors count to finish read/write operation (0..255)
12     2      Data byte offset from start of the sector
14     2      reserved to store time (from last interrupt in current frame) when working with current byte started, to emulate working with disk exactly
16     1      reserved to store controller status byte.


'MDRV' chunk - Microdrive cartridge image

This chunk is introduced in version 2.4.0.8 of EmuZWin, having Interface-I support. Up to 8 such chunks can be in the EZX, with different Slot indexes.

offset size   description
0      4      name = 'MDRV'
4      4      size (size of entire chunk data).
8      1      Slot index (1..8)

9      1      Motor On (1) (should be so only for one of such chunks if any)
10     1      Current Sector (0..253)
11     2      Current Position in the Sector (0..542)
13     1      GAP Count (0..21)
14     543*254=137922 All sectors data
137936 1      Write Protected flag (1)

137937 n      Filename (null-terminated string)


'DISD' chunk - +D / Disciple disk image

This chunk is introduced in version 2.4 of EmuZWin, having +D/Disciple support.

offset size   description
0      4      name = 'DISD'
4      4      size (size of entire chunk data).
8      1      Drive number (0 or 1)

9      1      bit0: Write protected (1),
              bit1: Double Density (sector size=512 bytes)
      bits 2-7: reserved (0)
10     1      Current Track (0..79)
14     2*80*10*256 or 2*80*10*512 All sectors data in .MGT order

      (side 0-track0, side1-track0, side0-track1, ..., side1-trak79)
137937 n      Filename (null-terminated string)


'DISC' chunk - +D / Disciple controller and other emulation state

This chunk is introduced in version 2.4 of EmuZWin, having +D/Disciple support.

offset size   description
0      4      name = 'DISC'
4      4      size (size of entire chunk data, 16391).
8      1      Current drive number (0 or 1)

9      1      Last Command Issued
10     1      Track register (0..79)
11     1      Sector register (0..9)
12     1      Side selected (0..1)
13     1      Direction for seek operation (0 or 1-forward, FF-back)
14     1      Operation (1-read 1 sector; $81-read M sectors;
      2-write sector; $82-write M sectors; 3-read address)
15     8192   ROM content
16     8192   RAM content


'PRVW' chunk - Preview bitmap

This chunk is introduced in version 2.2, and allows to pass any bitmap as a preview image. Such bitmap should be returned as a single chunk in the additional stream, if any. It is ignored excluding case, when a plugin is called to return Screen Only.

offset size   description
0      4      name = 'PRVW'
4      4      size (size of entire chunk data).

8      (size) bitmap file image.


'MULT' chunk - Multicolor settings

This chunk is introduced in version 2.3, and allows to save/restore multicolor settings selected for a certain Spectrum program.

offset size   description
0      4      name = 'MULT'
4      4      size (size of entire chunk data).

8      1      Multicolor: 0 - off, 1 - on
9      1      Timing parameter: 0 - Auto (not used), 1 - 48K, 2 - 128K, 3 - 128K+2,
              4 - 128K+2A/+3, 5 - Pentagon, 6 - Custom. Anyway, if settings below
              are not the same as "selected", those are used (like for Custom).
10     1      TStates per line (224 or 228)
11     2      Lines per frame (311..320)
13     4      TStates per frame total (can be larger then [TStates per line] * [Lines per frame])
17     4      TStates before int (0..[TStates per frame-1])
21     4      TStates before paper (0..[TStates per frame] - [TStates per line]*192 - 1)
25     2      ULA buffer (-57..+57) as smallint
27     8      Contended RAM banks 0,1,..,7 (0 - not contended, 1 - contended)
35     2      Contended ports FE and FD (0 - not contended, 1 - contended)
37     1      Emulate IN FF (0 - not emulate, always FF; 1 - emulate)
38     1      Emulate "snow" ULA bug (0 - not emulate, 1 - emulate)
39     1      -- reserved --
40     8      ULA Delay Sequence (8 delays, e.g. 6,5,4,3,2,1,0,0)


'AYST' chunk - AY Emulation state

offset size   description
0      4      name = 'AYST'
4      4      size (size of entire chunk data).

8      len    some AY state variables (counters, flags, etc.)


'GFXM' chunk - GFX Memory bank

This chunk is introduced in version 2.4, and allows to save/restore GFX memory bank information. GFX extension allows playing games in 256 colors mode, which was introduced fist time it a great Sp256 Spectrum emulator. In GFX Memory bank, each 8 bytes are correspondent to a one byte in usual Spectrum memory, and contains an index in the standard system 256-color palette used in old VGA 320x200x256 mode (the last 64 values are to be mixed with the old style attribute). There is not necessary to store GFXM chunk in case when it contains only 0 values. See also other GFX extension chunks below, and read about GFX extension in a separate html file provided.

offset size   description
0      4      name = 'GFXM'
4      4      size (size of entire chunk data).

8      1      Bank: 0..7 - RAM bank; 16 - S128 ROM; 17 - S48 ROM; 18 - TR-DOS ROM.
9      131072 GFX bytes, one byte for each bit in the correspondent Spectrum memory bank.
              The Less Significant Byte in each eight bytes sequence is the first.


'GFXR' chunk - GFX Registers

This chunk is introduced in version 2.4, and allows to save/restore GFX registers information. While processing GFX-machine parallel to working with the main ZX-machine which actually knows nothing about GFX, when data are loading from a memory to registers in the main ZX-machine, correspondent GFX-memory bytes are loaded to certain GFX-registers also having 8 bytes for each 8-bits ZX-register and 16 bytes for each 16-bits main ZX-register. And while storing bytes from the main ZX-registers to memory, correspondent GFX-registers are also stored to corresponent GFX-memory. This allows easy trace GFX-sprites independantly of a way how it achieve screen video-buffer, directly copying it (LDI/LDIR/LDD/LDDR) or via memory-register-memory operations. Also some operations could be applied to GFX registers while the main ZX-machine does these operations on its normal registers (shifts, masking, etc.). In many cases, restoring CPU registers is not absolutely necessary in all cases since GFX-image is restored soon after loading the state. But sometimes this is necessary therefore (e.g., in certain games, it is possible that alternative set of registers is reloaded very rare, and their GFX-mirror contains important informations necessary to create true 256-colors video image).

offset size   description
0      4      name = 'GFXR'
4      4      size (size of entire chunk data).

8      8      GFX_F
16     8      GFX_A
24     8      GFX_C
32     8      GFX_B
40     8      GFX_E
48     8      GFX_D
56     8      GFX_L
64     8      GFX_H
72     8      GFX_IXL
80     8      GFX_IXH
88     8      GFX_IYL
96     8      GFX_IYH
104    8      GFX_SP low
112    8      GFX_SP high
120    8      GFX_I
128    8      GFX_F'
136    8      GFX_A'
144    8      GFX_C'
152    8      GFX_B'
160    8      GFX_E'
168    8      GFX_D'
176    8      GFX_L'
184    8      GFX_H'

              The Less Significant Byte in each eight bytes sequence is the first.


'GFXB' chunk - GFX Background

This chunk is introduced in version 2.4, and allows to save/restore GFX background image. It is used to fill the background before rendering video-buffer. For compatibility with original Sp256 converted games, background of size 300x200 are allowed, not only 256x192. A game can have several backgrounds, and to apply certain one some rules are used in EmuZWin: two selected colors in the palette (with indeces #XX and #YY) are used to create matching mask. The mask is satisfied if all the bits in video-buffer corresponding to a pixel with the index #XX are 0, and all the bits corresponding to #YY are 1. If the mask is satisfied, correspondent background becomes current.

offset size   description
0      4      name = 'GFXB'
4      4      size (size of entire chunk data).

8      2      Background number 0..16383.
              When a background with certain number nn selected, a correspondent palette nn also applied if any (or 00, if there are no palette nn).
14     2      Width; (values 320x200 and 256x192 are allowed only).
16     2      Height; 
18     Width x Height - Pixels data.


'GFXP' chunk - GFX Palette

This chunk is introduced in version 2.4, and allows to save/restore GFX palette. By default, standard system palette used applied in old 320x200x256 VGA mode.

offset size   description
0      4      name = 'GFXP'
4      4      size (size of entire chunk data).

8      2      Palette number 0..16383. Just to store number nn of a *.Pnn file.
10     768    256 palette entries R, G, B.


'GFXS' chunk - GFX Screen XOR back buffers

This chunk is introduced in version 2.4, and its purpose is to store special screen buffers used in GFXScreenXORbuffered mode.

offset size   description
0      4      name = 'GFXS'
4      4      size (size of entire chunk data).

8      147456 buffers data.


'GFXC' chunk - GFX Configuration

This chunk is introduced in version 2.4, and its purpose is to store configuration. For old 256 color games stored in directories as a set of separate files (*.GFX, ROMn.GFX, *.GFn, *.GFA, *.GFB, *.GFC, *.Bnn, *.Pnn, *.PAL, *.CFG) a file with an extension .CFG is used to store such configuration parameters. In EZX, this file just stored as a long ANSI string.

offset size   description
0      4      name = 'GFXC'
4      4      size (size of entire chunk data).

8      size   Configuration file strings, separated by #13#10 or #13 as in usual text file.

Configuration strings (default values are shown):

GFXLeveledXOR=0
GFXLeveledOR=0
GFXLeveledAND=0
GFXScreenXORBuffered=0
UpColorsMixed=64
DownColorsMixed=0
UpMixChgBright=0
DownMixChgBright=0
UseBrightInMix=0
UpMixPaper=0
DownMixPaper=0
BkMixed=0
BkMixBkAttr=0
BkOverFF=1

GFXLeveledXOR: while XORing two GFX bytes, MAX function used to get result. Actually, for xor only A xor A gives 00, in all other cases A xor B = max(A,B) when this option is on.

GFXLeveledOR: while ORing two GFX bytes, MAX function used to get result when this option is on.

GFXLeveledAND: while ANDing two GFX bytes, MIN function used to get result: A and B = min(A,B) when this option is on.

GFXScreenXORBuffered: if 1, special sequence [XOR A,(HL);LD (HL),A] when HL is between 4000H and 57FFH is recognized as xor with screen. In such case, previous GFX data is stored in special buffer together with data (in GFX.A) used to xor it. If such operation is executed again for such address, then for those XOR-data in GFX.A, which are the same, just previous GFX data value is restored.

UpColorsMixed: if 0, there are no mixing at all for up colors in the palette. By default, up 64 colors (with indeces from 192 to 255) are mixed with usual attribute. Maximum value (plus DownColorsMixed) is 128.

DownColorsMixed: if 0, there are no mixing at all for down colors in the palette. By default, only up 64 colors (with indeces from 192 to 255) are mixed with usual attribute and no down colors are mixed. Maximum value for UpColorsMixed+DownColors is 128.

UpMixChgBright
: 0..100 percents (default 0), defines which part of mixed result is affected by the bright of an attribute rather then by its color.

DownMixChgBright: the same as above but for down mixed colors bank.

UseBrightInMix: By default, only 3 lower bits in the attribute byte correspondent to a foreground color are used for mixing last 64 colors in the palette. If 1, then brightness bit also used to mix with.

UpMixPaper: by default, mixing is done always with attribute ink color. Setting this option to 1 provides mixing with a paper color only - for upper mixed colors bank.

DownMixPaper: the same as UpMixPaper, but for down mixed colors bank.

BkMixed: if 1, then colors in the background with indeces under DownColorsMixed and above UpColorsMixed are are mixed with the attribute.

BkMixBkAttr: if 1, and BkMixed=1, then background pixels with indeces under DownColorsMixed and above UpColorsMixed are mixed with back attribute rather then with fore attribute.

BkOverFF: background pixels are overriding also FF value from GFX, but not in case when a correspondent attribute has fore color 7 (white).

Also, a number of lines can be there which define probes for background. Those must have following format:

NN: addr [ & mask1, mask2, ..., maskN ] = [ byte1, byte2, ..., byteN ] [; addr [ masks ] = [ bytes ] ]...

where:
NN - background number (at least two decimal digits, e.g. 00 for background number 0);

addr - decimal or hexadecimal probe address (e.g. 4000H);

& masks - a list of comma separated bytes used as masks while probing following bytes;

bytes - a list of comma separated bytes, which are compared with correspondent memory bytes at address addr, addr+1, ..., addr+N-1 correspondently to byte1, byte2, ..., byteN. If masks available those are masking correspondent memory bytes before comparing with bytes (e.g., if 98H is probed with mask FEH, both values 98H and 99H at that memory are satisfying).

All the sequences listed (semicolon separated) in one line are defining one probe which is satisfying only if all the masked comparisons are satisfied. There is possible a situation when several probes are satisfying correspondent to different backgrounds. In such case a background selected correspondent to the longest probe among winning (i.e. having more bytes to compare), and among all winning probes of the same length - the first one.


'MAP ' chunk - MAP created with Map Builder

This chunk is introduced in version 2.3, and allows to save/restore navigation map created with Map Builder.

offset size   description
0      4      name = 'MAP '
4      4      size (size of entire chunk data).

8      1      Map Style: 0 - Undeterminated, 1 - Flat, 2 - Isometric
9      2      ShpLeft    |
11     2      ShpTop     | Cutting rectangle
13     2      ShpRight  |
15     2      ShpBottom |
17     6144   ShpMask: bit=0, if a pixel is in the image, 1 - transparent
6161   4      FrameCount = count of frames in the map
6165   4      CurFrameIdx = index of the current frame in the map
6169   2      Scale * 10000 (e.g. 4000 for scale 0,4)
6171   1      Show Room Numbers (1 - show, 2 - not show)
6172   2      ZeroPt (X:byte 0..255, Y:byte 0..191), used to detect move direction
6174   4      Additional header length (ALen), in version 2.3 always 0
6178   (ALen) Additional header, in version 2.3 empty
----------- start the first frame here:
0      6912   The first frame image as in SCR-file (copy of the video page of the Spectrum)
6912   4      FromFrameIdx = zero-based index of the frame, from which
              the given frame is come in
              (-1 if this information is not available)
6916   4      X-coordinate on the map (in the scale 1.0)
6920   4      Y-coordinate on the map (in the scale 1.0)
6924   2      Level (small int, -32767..+32767), if value = 8000 hex, additional extention used (see below)
------------- other frames are following here (FrameCount frames total).

If additional extension used for a frame (Level = 8000 hex), following fields are added:
6926   2      Level'
6928   2      Count of user-defined marks
------------- First mark started here
6930   1      Mark Type: 0 - Rectangle, 1 - Circle, 2 - Join between frames
------ For Rectangle or Circle marks:
6931   3      BGR color the frame
6934   2      X-offset from upper left corner of the frame (when scale = 1.0),
              -32768..32767
6936   2      Y-offset
6938   2      width
6940   2      height
6942   4      Bitmap size used as a mark
6946   (size) Bitmap used as a mark (for circle, rounded corners are not drawn)
------ For join-between marks:
6931   3      BGR color of join line
6934   2      X-offset
6936   2      Y-offset
6938   4      Another (joined) frame index
6942   1      Line width (0..2)
6943   2      X-offset of another end point from the upper-left corner of the joined
              frame, when scale = 1.0
6945   2      Y-offset
6947   1      End point 1 shape (0 - no shape, 1 - arrow to)
6948   1      End point 2 shape (0 - no shape, 2 - arrow to)  
------------- then the next mark is following


'NRLZ' chunk - NetPlay server rules:

offset size   description
0      4      name         = 'NRLZ'
4      4      size         = size of data
8      size   rules data (screen to show - 6912 bytes = pixels + attributes 
		in reordered sequence Y=0,1,...192, then screen mask -
		6144 bytes - pixels only, in the same order, then 4 bytes
		defining the rule. Such data are stored for each rule in
		the set).

'NSEP' chunk - NetPlay server keyboard separation:

offset size   description
0      4      name         = 'NSEP'
4      4      size         = size of data (6*9 = 54 bytes)
8      size   9 bytes of keyboard mask for each of 6 players.
		Every mask byte contains bits 0-4 masking for a port.
		Ports sequence is: 
		port #FEFE; port #FDFE; port #FBFE; port #F7FE; 
		port #EFFE; port #DFFE; port #BFFE; port #7FFE; 
		port #1F (Kempston joystick port)

'TAPC' chunk - call stack of tape recorder:

offset size   description
0      4      name         = 'TAPC'
4      4      size         = size of data (must be a multiple of 4)
8      size   size/4 dwords (return positions)
Data of this chunk has its own format, may be not so compact, but
very easy to implement and therefore allowing to represent any tape
recording in exact pulses. See description of tape format below.

'ITPC' chunk - call stack of tape recorder in its initial state:

offset size   description
0      4      name         = 'ITPC'
4      4      size         = size of data (must be a multiple of 4)
8      size   size/4 dwords (return positions)

'TAPL' chunk - loop stack of tape recorder:

offset size   description
0      4      name         = 'TAPL'
4      4      size         = size of data (must be a multiple of 8)
8      size   size/8 qwords (counters and correspondent jump positions)

'ITPL' chunk - loop stack of tape recorder in its initial state:

offset size   description
0      4      name         = 'ITPL'
4      4      size         = size of data (must be a multiple of 8)
8      size   size/8 qwords (counters and correspondent jump positions)

'TAPE' chunk - Tape image

This chunk usually is located first, but it is described here since it has most complicated structure and can contain a lot of sub-structures listed below

offset size   description
0      4      name = 'TAPE'
4      4      size (size of entire chunk data).

8      (size) tape data, see its format below.


DESCRIPTION OF TAPE FORMAT USED INTERNALLY IN EZX FILE FORMAT

Tape data contains blocks of variable length, identifying by the first byte. Format of each block is very different, but it is not planned to be extended or changed later, since all possible requirements can be expressed using existing blocks.


ID=0 Standard Data Block (TAP)

offset size   description
0      2      Length of Data
2      Length Data

Such block does not require pilot or synchronization defined separately (these are generated before the block). But if a pause needed after the block it should be defined as a separate tones block.


ID=1 Tones Data Block

offset size   description
0      2      Length of pulse in Spectrum T-states (1/350000 sec)
2      4      Tones count (actually bits count in following data)
6      (TonesCount+7)/8 bytes. Each bit represents one tone of
       high (1) or low (0) level. Bits in each byte are scanned
       from b7 to b0.

See also block ID=0C (Pure Data) below.


ID=2 Stop Command

No data. Tape is stopped until user click toolbar button "Play".


ID=3 Jump

offset size   description
0      4      Integer offset relative to start position of the
              block (just after ID byte).

Changes order of block to read. A byte pointed by the offset must be ID of the block to jump to.


ID=4 Loop start

offset size   description
0      4      Loop count.


ID=5 Loop end

No data.


ID=6 Call

offset size   description
0      4      Integer offset to a block called.


ID=7 Return from call

No data.


ID=8 Menu to display or text

offset size   description
0      1      Number of menu items. If 1, this block is just
              Text (can be used to place a description in a
              catalog).
1      4      Jump offset (relative to size byte, located just
              after ID byte).
5      Zero-terminated ASCII string.
x      4      Jump offset for second menu item.
..............


ID=9 Jump if S128

offset size   description
0      4      Integer jump offset.


ID=0A Message to display

offset size   description
0      2      Time to display message (0 - until OK pressed).
2      Zero-terminated ASCII string (#0D character to separate
       lines if necessary).


ID=0B Wait until IN (FE)

No data. This command can be added to stop playing tape until data from port FE requested from the Spectrum.


ID=0C Pure data

offset size   description
0      2      L0 = Length of pulse correspondent to value "0"
              in Spectrum T-states (1/350000 sec)
2      2      L1 = Length of pulse correspondent to value "1" in Spectrum T-states (1/350000 sec)
4      4      Tones count (actually bits count in following data)
8      (TonesCount+7)/8 bytes. Each bit represents one encoded value
       0 or 1, each of those will be decoded to a pare of low and high
       level pulse each of correspondent length (L0 for value 0, L1 for
       value 1). Bits in each byte are scanned from b7 to b0.

This command is added in version 2.1 (release 2.0) and is useful to represent TZX Pure Data Block or data part of Turbo Loading Data Block, especially in case when Zero Pulse Length and One Pulse Length are not relative to each other as p:q (p,q=1..8), but are very far from such releation, e.g. 1:1,8556.


Last update: 3-Nov-2003

http://bonanzas.rinet.ru mailto: bonanzas@online.sinor.ru