UDI format
UDI Disk Image Format
The UDI format was created for storing faithful disk images for emulation.
This format is member of the Complex Disk Image Formats and contains almost all information about a disk.
UDI file structure
UDI images can store any type of floppy disk or even Microdrive tape data.
UDI store raw track data: bytes and clock marks, as recorded on the disk. Because gap and mark bytes are recorded and data are not interpreted (e.g. splitted up sectors, etc), we can build a very faithful disk layer emulation based on UDI image format.
File Header
UDI files start with UDI! signature (magic bytes).
Header contain data about number of sides and number of tracks.
Data
Track data follow the “alt” schema:
- Side: 0 Track: 0
- Side: 1 Track: 0
- Side: 0 Track: 1
...
- Side: 0 Track: last
- Side: 1 Track: last
Track data contain information about track type (e.g. MF or MFM coded, weak data, etc.), track length and a CRC check.
Further details can be found in the following specification.
UDI: Ultra Disk Image file format Version 1.0
UDI file structure
Offset Length Comment 0x0000 16 UDI file header 0x0010 EXTHDL Extended header 0x0010 + EXTHDL TRSL Tracks data 0x0010 + EXTHDL + TRSL 4 CRC32 CRC32 of the file
UDI file header
Offset Length Comment 0x0000 4 Signature "UDI!" 0x0004 4 File size - 4 (last 4 bytes is checksum) 0x0008 1 Version 0x00 - Version 1.0
0x0009 1 Number of cylinders - 1 e.g. 0x4F for 80 cylinders on disk
0x000A 1 Number of sides - 1 0x00 Single sided disk 0x01 Double sided disk 0x02..0xFF reserved
0x000B 1 Unused (should be 0) 0x000C 4 EXTHDL - Extended header size
Extended header
Offset Length Comment 0x0000 EXTHDL Unspecified data
Tracks data
Offset Length Comment 0x0000 TRLEN0 1st. track data 0x0000 + TRLEN0 TRLEN1 2nd. track data 0x0000 + TRLEN0 + TRLEN1 TRLEN2 3rd. track data … … … 0x0000 + TRLEN0 + TRLEN1 + … + TRLENLAST-1 TRLENLAST Last track data
- TRSL = TRLEN0 + TRLEN1 + … + TRLENLAST
Track data order in file Single sided disk Double sided disk Track No Side Cylinder No Side Cylinder No 0 0 or A 0 0 or A 0 1 0 or A 1 1 or B 0 2 0 or A 2 0 or A 1 3 0 or A 3 1 or B 1 … … … … … Last 0 or A Last 1 or B Last
Track data format
Offset Length Comment 0x0000 1 Track type 0x00 - MFM data 0x01-0xff reserved
0x0001 2 TLEN Track data size in bytes include MARKs GAPs etc.
0x0003 TLEN Data bytes 0x0003 + TLEN CLEN Track clock marks where CLEN = TLEN / 8 + ( TLEN % 8 + 7 ) / 8 One bit corresponds with one byte of raw track data 0 - byte with normal CLK (normal data) 1 - byte with mark CLK (for index label 0xA1 ¨ 0xC2) For example: { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 } where 0xA1 - MFM markers for this raw data, bits array store as one byte - 0x0B unused last bits should be 0.
- TRLENN = 3 + TLENN + CLENN
Algorithm of calculation CRC32 for UDI file
DWORD fileSize; // Size of file
BYTE *buf; // Pointer to file data
long CRC = 0xffffffff;
for( DWORD i = 0; i < fileSize; i++ )
{
DWORD temp;
CRC ^= -1 ^ *(((unsigned char*)buf)+i);
for( BYTE k = 8; k--; )
{
temp = -(CRC & 1); CRC >>= 1; CRC ^= 0xedb88320 & temp;
}
CRC ^= -1;
}
Appendix
- If the file signature is udi! (written in small letters) instead of UDI!, then data is compressed. The compression algorithm has not yet been determined but likely will be similar to TELEDISK's compression algorithm.
Author of UDI file format
- Author of UDI file format is Alex Makeev.
- This description based on UDI file format Version 1.0 final! Revision 24 March, 2002
- Original doc: http://www.zxmak.narod.ru/docs.htm
Notes
- All calculations made with integer arithmetic (e.g. 15 / 8 gives 1 )
- Operator % means modulus of, as used in C language
- All multibyte values in Little Endian order, (e.g. TLEN = TLEN0 + 256 × TLEN1)
UDI: Ultra Disk Image file format Version 1.1
This is an 'smooth' extension of original UDI specification.
This version extend only the 'track data format' section.
This version drop the specification of the compresed UDI files idea with udi! (written in small letters) signature, but add a compressed track container type for similar purpose. So all v1.1 UDI files start with UDI! (written in capital letters) signature.
Whit this extension the UDI format can store floppy disk (and microdrive) data more faithfully then other disk image formats.
Track data format
Offset Length Comment 0x0000 1 Track type 0x00 - MFM data 0x01 - FM data 0x02 - mixed MFM/FM data 0x80 - 'floating' or 'weak' MFM data 0x81 - 'floating' or 'weak' FM data 0x82 - 'floating' or 'weak' mixed MFM/FM data 0x83 - 'floating' or 'weak' data with multiple read 0xe0 - microdrive 'track' 0xf0 - zlib 'compressed' track container 0x03-0x7f and 0x81-0xef reserved 0xf1-0xff reserved for other compressions (e.g. bzip2 and lzma)
0x0001 TDATAL Track data as described later
- TRLENN = 1 + TDATALN
Track data for type 0x00 (MFM) and 0x01 (FM)
Offset Length Comment 0x0000 2 TLEN Track data size in bytes include MARKs GAPs etc.
0x0002 TLEN Data bytes 0x0002 + TLEN CLEN Track clock marks where CLEN = TLEN / 8 + ( TLEN % 8 + 7 ) / 8 One bit corresponds with one byte of raw track data 0 - byte with normal CLK (normal data) 1 - byte with mark CLK (for index label 0xA1 ¨ 0xC2) For example: { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 } where 0xA1 - MFM markers for this raw data, bits array store as one byte - 0x0B unused last bits should be 0.
- TDATALN = 2 + TLENN + CLENN
Track data for type 0x02 (mixed MFM/FM)
Offset Length Comment 0x0000 2 TLEN Track data size in bytes include MARKs GAPs etc.
0x0002 TLEN Data bytes 0x0002 + TLEN CLEN Track clock marks where CLEN = TLEN / 8 + ( TLEN % 8 + 7 ) / 8 One bit corresponds with one byte of raw track data 0 - byte with normal CLK (normal data) 1 - byte with mark CLK (for index label 0xA1 ¨ 0xC2) For example: { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 } where 0xA1 - MFM markers for this raw data, bits array store as one byte - 0x0B unused last bits should be 0.
0x0002 + TLEN + CLEN MLEN MF marks where MLEN = CLEN One bit corresponds with one byte of raw track data 0 - byte coded with MFM 1 - byte code with FM unused last bits should be 0.
- TDATALN = 2 + TLENN + 2×CLENN
Track data for type 0x80 (MFM) or 0x81 (FM) "floating" or "weak" data chunk
Offset Length Comment 0x0000 2 TLEN Track data size in bytes include MARKs GAPs etc.
0x0002 TLEN Data bytes 0x0002 + TLEN CLEN Track clock marks where CLEN = TLEN / 8 + ( TLEN % 8 + 7 ) / 8 One bit corresponds with one byte of raw track data 0 - byte with normal CLK (normal data) 1 - byte with mark CLK (for index label 0xA1 ¨ 0xC2) For example: { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 } where 0xA1 - MFM markers for this raw data, bits array store as one byte - 0x0B unused last bits should be 0.
0x0002 + TLEN + CLEN FLEN Float marks where FLEN = CLEN One bit corresponds with one byte of raw track data 0 - byte not 'floating' ( not 'weak') 1 - byte 'floating' ('weak') unused last bits should be 0.
- TDATALN = 2 + TLENN + 2×CLENN
Track data for type 0x82 (mixed MFM/FM) "floating" or "weak" data chunk
Offset Length Comment 0x0000 2 TLEN Track data size in bytes include MARKs GAPs etc.
0x0002 TLEN Data bytes 0x0002 + TLEN CLEN Track clock marks where CLEN = TLEN / 8 + ( TLEN % 8 + 7 ) / 8 One bit corresponds with one byte of raw track data 0 - byte with normal CLK (normal data) 1 - byte with mark CLK (for index label 0xA1 ¨ 0xC2) For example: { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 } where 0xA1 - MFM markers for this raw data, bits array store as one byte - 0x0B unused last bits should be 0.
0x0002 + TLEN + CLEN MLEN MF marks where MLEN = CLEN One bit corresponds with one byte of raw track data 0 - byte coded with MFM 1 - byte code with FM unused last bits should be 0.
0x0002 + TLEN + 2 * CLEN FLEN Float marks where FLEN = CLEN One bit corresponds with one byte of raw track data 0 - byte not 'floating' ( not 'weak') 1 - byte 'floating' ('weak') unused last bits should be 0.
- TDATALN = 2 + TLENN + 3×CLENN
Track data for type 0x83 ("floating" or "weak" data chunk with multiple 'read')
Offset Length Comment 0x0000 2 TLEN + (NUM - 1) Track data size in bytes include MARKs GAPs etc. TLEN must be aligned to 8, so the lowest 3 bit always 0. NUM must be between 1 and 8.
0x0002 2 OFFS / 8 OFFSet from the start of the previouse Track OFFS aligned to 8.
0x0004 TLEN First alternate, Data bytes 0x0004 + TLEN CLEN First alternative, Track clock marks where CLEN = TLEN / 8 One bit corresponds with one byte of raw track data 0 - byte with normal CLK (normal data) 1 - byte with mark CLK (for index label 0xA1 ¨ 0xC2) For example: { 0xA1,0xA1,0x00,0xA1,0xFE,0x00,0x00,0x01 } where 0xA1 - MFM markers for this raw data, bits array store as one byte - 0x0B start and length are 8 bit aligned, so there are no unused bits.
0x0004 + TLEN + CLEN TLEN Second alternative, Data bytes 0x0004 + 2 × TLEN + CLEN CLEN Second alernative, Track clock marks ... continues until all data chunk ...
- TDATALN = 4 + TLENN + CLENN
- where TLEN = (TLEN + (NUM - 1)) & 0xfff8
- where NUM = ((TLEN + (NUM - 1)) & 0x0007) + 1
- This track data is represent "alternative" read of the given part (OFFS, TLEN) of the previouse track (type: 0x00, 0x01 or 0x02)
- This track must be preceeded by a full track (type: 0x00, 0x01 or 0x02). We can define several not overlapped alternative read areas. e.g.:
- TrackN data (0x00); 3 × TrackN,offs1,len1; 2 × TrackN,offs2,len2; TrackN+1 data(0x00); e.t.c.
####### TrackN data (type: 0x00) ######## ## TrackN,offs1,len1-1 ## ## TrackN,offs1,len1-2 ## ## TrackN,offs1,len1-3 ## ## TrackN,offs2,len2-1 ## ## TrackN,offs2,len2-2 ## ####### TrackN+1 data (type: 0x00) ########
Track data for type 0xe0 Microdrive cartridge track
Offset Length Comment 0x0000 2 TLEN / 8 Track data size in bytes include GAPs etc.
0x0002 TLEN Data bytes 0x0002 + TLEN BLEN Track bad bytes marks where BLEN = TLEN / 8 One bit corresponds with one byte of raw track data 0 - byte usable 1 - byte unusable (bad)
- TDATALN = 2 + TLENN
- Note: on Microdrive tapes the data recorded in two paralell tracks (with a standard stereo
- tape head arrangement), but the Interface I hardware deal about multiplexing/demultiplexing
- data so, ZX Spectrum never see the two track separately.
- Note2: the track length is always 8 byte aligned, so if your data cannot fit on an 8 byte boundary, you must pad with unusable bytes. This is not unnatural because where the microdrive endless tape spliced there are several bad bytes.
Data for type 0xf0 ("compressed" track data)
Offset Length Comment 0x0000 2 DLEN - 1 Compressed data size minus one.
0x0002 1 Track type This is the track type of uncompressed data, so emulators can calculate uncompressed length and make decision about the track without uncompressing the data (e.g. discard weak track data if it not supported, etc...)
0x0003 2 TLEN This is the TLEN of uncompressed data, so emulators can calculate uncompressed length
0x0005 DLEN Data bytes. If uncompress this data with zlib it gives track data as defined in Tracks data without Track type and TLEN.
- TDATALN = 6 + DLENN
- This track is a container which hold headerless track data in a compressed way.
- So after uncompression, we get a whole track without Track type and TLEN
- as defined in Tracks data.
- Only 0x00, 0x01, 0x02, 0x80, 0x81, 0x82 and 0x83 are the valid Track types, so
- compressed tracks cannot be nested.
- Compression method is the zlib deflate algorithm with standard zlib header.
- Uncompressed data length can be calculated from Track type and TLEN
- according to section Track data for type 0x00 (MFM) and 0x01 (FM)
- For e.g. if Track Type is 0x00 (MFM track), then track length is
- TDATAL = 3 + TLEN + TLEN / 8 + (TLEN % 8 + 7) / 8 and uncompressed data
- length is TDATAL - 3 (because compressed data does not include Track type and TLEN.
- Note: The compressed size maximum is 65536 byte, so if a track compressed size greater than
- 65536 it can be recorded only as uncompressed track. We have to note that: the highest capacity
- (2.88MB/ED) floppy disk's raw track size is about 50KB, so this limit looks acceptable.