*** SixPack Zipcode (6-file version, 1!!xxxxx, 2!!xxxxx, etc) *** Document revision 1.1 This is another rare form of ZipCode, spanning 6 archive files, and hence the use of the name SixPack. Note the difference in the filename and file structure from a 4-pack ZipCode. Name Track Range -------- ----------- 1!!xxxxx 1 - 6 2!!xxxxx 7 - 12 3!!xxxxx 13 - 18 4!!xxxxx 19 - 25 5!!xxxxx 26 - 32 6!!xxxxx 33 - 35 (or 40 for 40-track images) The format for these is *nothing* like the 4-pack. It contains no compression and no track/sector references. Rather, all the sector data is stored in GCR code (Group Code Recording). GCR is the method used to store information, at the lowest level, on a 1541 diskette. It converts 4-bit nybbles (2 nybbles per byte, upper 4 bits and lower 4 bits) into an encoded 5-bit GCR code. The conversion chart for 4-bit to 5-bit conversion is as follows: Hex Binary GCR Hex Binary GCR --- ------ ----- --- ------ ----- 00 - 0000 - 01010 08 - 1000 - 01001 01 - 0001 - 01011 09 - 1001 - 11001 02 - 0010 - 10010 0A - 1010 - 11010 03 - 0011 - 10011 0B - 1011 - 11011 04 - 0100 - 01110 0C - 1100 - 01101 05 - 0101 - 01111 0D - 1101 - 11101 06 - 0110 - 10110 0E - 1110 - 11110 07 - 0111 - 10111 0F - 1111 - 10101 If you look over the GCR table, there are two details that should be noted. 1. You *cannot* combine any two GCR bytes into numbers that contain more than 10 consecutive 1-bits (the most we can get is 8). Ten (or more) consecutive 1-bits is used for a SYNC mark, used to tell the disk controller that sector data is coming up. (In actual fact, the 1541 records an overkill of 40 sequential 1-bits to the disk as a SYNC mark to ensure the controller can find the mark!) 2. There will never be any more than two consecutive 0-bits. This is done to insure the accuracy of clocking data back to the 1541 controller. Too many zero bits, and the clock will go out of sync. Using the above table, let's convert some numbers. For reasons I will explain later, we must work in groups of four bytes in order to convert normal HEX to GCR. Using these HEX numbers... 0D F5 E4 37 now, split these values into nybbles and convert to binary... 0 D F 5 E 4 3 7 ---- ---- ---- ---- ---- ---- ---- ---- 0000 1101 1111 0101 1110 0100 0011 0111 convert nybbles to GCR using the conversion table... 0000 1101 1111 0101 1110 0100 0011 0111 ----- ----- ----- ----- ----- ----- ----- ----- 01010 11101 10101 01111 11110 01110 10011 10111 now, recombine the bit into groups of 8... 01010 11101 10101 01111 11110 01110 10011 10111 | || || || || | | byte 1|| byte 2 || byte 3 || byte 4 || byte 5| | || || || || | ------- ---------- --------- ---------- ------- 01010111 01101010 11111111 00111010 01110111 and convert back to HEX... 01010111 01101010 11111111 00111010 01110111 -------- -------- -------- -------- -------- 57 6A FF 3A 77 So, now we have converted a group of 4 bytes into 5 GCR bytes. The reason we must encode in groups of 4 is that it is the *minimum* number of bytes which, when converted to GCR bits, is divisible by 8 bits without any remainder... 1 byte would be 10 bits, 2 bytes would be 20, 3 bytes would be 30, but 4 bytes is 40 bits, divisible by 8 since it leaves us with 5 groups of 8 bits. Now that we have a foundation of GCR encoding, we can begin to analyse the layout of the 6-pack zipcode. Below is a sample of the first file (1!!xxxxx): 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: FF 03 24 52 55 25 29 4B 9A E7 25 55 55 52 55 35 úú$RU%)Kšç%UURU5 0010: 2D 4B 9A E7 25 55 55 52 54 A5 49 4B 9A E7 25 55 -Kšç%UURTĄIKšç%U 0020: 55 52 54 B5 4D 4B 9A E7 25 55 55 52 55 65 39 4B URTµMKšç%UURUe9K 0030: 9A E7 25 55 55 52 55 75 3D 4B 9A E7 25 55 55 52 šç%UURUu=Kšç%UUR 0040: 54 E5 59 4B 9A E7 25 55 55 52 54 F5 5D 4B 9A E7 TĺYKšç%UURTő]Kšç 0050: 25 55 55 52 55 A5 25 4B 9A E7 25 55 55 52 55 B5 %UURUĄ%Kšç%UURUµ 0060: 65 4B 9A E7 25 55 55 52 54 95 69 4B 9A E7 25 55 eKšç%UURT•iKšç%U 0070: 55 52 55 95 6D 4B 9A E7 25 55 55 52 55 E5 35 4B URU•mKšç%UURUĺ5K 0080: 9A E7 25 55 55 52 55 55 75 4B 9A E7 25 55 55 52 šç%UURUUuKšç%UUR 0090: 54 D5 79 4B 9A E7 25 55 55 52 55 D5 55 4B 9A E7 TŐyKšç%UURUŐUKšç 00A0: 25 55 55 52 57 25 A9 4B 9A E7 25 55 55 52 57 35 %UURW%©Kšç%UURW5 00B0: AD 4B 9A E7 25 55 55 52 56 A5 C9 4B 9A E7 25 55 ­Kšç%UURVĄÉKšç%U 00C0: 55 52 56 B5 CD 4B 9A E7 25 55 55 52 57 65 B9 4B URVµÍKšç%UURWeąK 00D0: 9A E7 25 55 55 29 0F 05 C0 99 00 02 C8 D0 D4 A9 šç%UU)úúŔ™úúČĐÔ© 00E0: 02 8D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 úŤúúúúúúúúúúúúúú 00F0: 00 00 00 00 00 00 00 00 00 41 4D 45 3A 20 31 32 úúúúúúúúúAME:ú12 0100: 33 34 15 D4 B5 2D 4B 52 D4 B5 2D 4B 52 D4 B5 2D 34úÔµ-KRÔµ-KRÔµ- 0110: 4B 52 D4 B5 2D 4B 52 D4 B5 2D 4B 52 D4 B5 2D 4B KRÔµ-KRÔµ-KRÔµ-K 0120: 52 D4 B5 2D 4B 52 D4 B5 2D 4B 52 D4 B5 2D 4B 52 RÔµ-KRÔµ-KRÔµ-KR 0130: D4 B5 2D 4B 52 D4 B5 2D 4B 52 D4 B5 2D 4B 52 D4 Ôµ-KRÔµ-KRÔµ-KRÔ 0140: B5 2D 4B 52 D4 B5 29 4D 55 55 D4 A5 2D 4B 52 D4 µ-KRÔµ)MUUÔĄ-KRÔ 0150: B5 2D 4B 52 D4 B5 2D 4B 52 D4 B5 2D 4B 52 D4 B5 µ-KRÔµ-KRÔµ-KRÔµ Each file starts with a 3-byte signature, $FF, $03, and then either a $24 for a 35 track image, or a $29 for a 40 track image. 0000: FF 03 24 .. .. .. .. .. .. .. .. .. .. .. .. .. Track information follows, and is comprised of a 256 byte track descriptor block (mostly GCR encoded), followed by sector information at 326 bytes/sector. The track descriptor contains the header information of each sector in that track, as well as the number of sectors encoded on that track. They are stored in the descriptor block in linear order, from 0 to the maximum sector on that track. Note that each of the entries in the descriptor take 10 bytes, as 10 bytes (GCR) decodes to 8 bytes normal HEX. These also correspond to the header info on a real 1541 disk. Here is the layout (re-arranged from the above block)... Sec Byte CGR Contents Normal Contents (decoded) --- ---- ----------------------------- ------------------------- Sig Chk Sec Trk Id2 Id1 OffBytes 0 00: 52 55 25 29 4B 9A E7 25 55 55 08 02 00 01 31 32 0F 0F 1 0A: 52 55 35 2D 4B 9A E7 25 55 55 08 03 01 01 31 32 0F 0F 2 14: 52 54 A5 49 4B 9A E7 25 55 55 08 00 02 01 31 32 0F 0F 3 1E: 52 54 B5 4D 4B 9A E7 25 55 55 08 01 03 01 31 32 0F 0F 4 28: 52 55 65 39 4B 9A E7 25 55 55 08 06 04 01 31 32 0F 0F 5 32: 52 55 75 3D 4B 9A E7 25 55 55 08 07 05 01 31 32 0F 0F 6 3C: 52 54 E5 59 4B 9A E7 25 55 55 08 04 06 01 31 32 0F 0F 7 46: 52 54 F5 5D 4B 9A E7 25 55 55 08 05 07 01 31 32 0F 0F 8 50: 52 55 A5 25 4B 9A E7 25 55 55 08 0A 08 01 31 32 0F 0F 9 5A: 52 55 B5 65 4B 9A E7 25 55 55 08 0B 09 01 31 32 0F 0F 10 64: 52 54 95 69 4B 9A E7 25 55 55 08 08 0A 01 31 32 0F 0F 11 6E: 52 55 95 6D 4B 9A E7 25 55 55 08 09 0B 01 31 32 0F 0F 12 78: 52 55 E5 35 4B 9A E7 25 55 55 08 0E 0C 01 31 32 0F 0F 13 82: 52 55 55 75 4B 9A E7 25 55 55 08 0F 0D 01 31 32 0F 0F 14 8C: 52 54 D5 79 4B 9A E7 25 55 55 08 0C 0E 01 31 32 0F 0F 15 96: 52 55 D5 55 4B 9A E7 25 55 55 08 0D 0F 01 31 32 0F 0F 16 A0: 52 57 25 A9 4B 9A E7 25 55 55 08 12 10 01 31 32 0F 0F 17 AA: 52 57 35 AD 4B 9A E7 25 55 55 08 13 11 01 31 32 0F 0F 18 B4: 52 56 A5 C9 4B 9A E7 25 55 55 08 10 12 01 31 32 0F 0F 19 BE: 52 56 B5 CD 4B 9A E7 25 55 55 08 11 13 01 31 32 0F 0F 20 C8: 52 57 65 B9 4B 9A E7 25 55 55 08 16 14 01 31 32 0F 0F D2: 29 0F 05 C0 99 00 02 C8 D0 D4 Invalid DC: A9 02 8D 00 00 00 00 00 00 00 Invalid E6: 00 00 00 00 00 00 00 00 00 00 Invalid F0: 00 00 00 00 00 00 Invalid F6: 41 4D 45 3A 20 31 32 33 34 ASCII "AME: 1234" (not GCR, and possibly garbage, don't rely on it) FF: 15 Number of valid sectors contained with this track (21) Each sector header block is laid out in the following order (after decoding the 10 GCR bytes to 8 normal bytes): Byte: $00 - Header block descriptor value $08 01 - Header checksum (EOR of bytes 02-05) 02 - Sector number 03 - Track number 04 - Second byte of disk ID 05 - First byte of disk ID 06-07 - "OFF" bytes ($0F's). These "fill" up the header to make it a multiple of 4 bytes, necessary in order to convert it to GCR (as six bytes would be too short to convert) The entries for Sectors 17-20 will only be valid if the track being operated on has that many sectors in it. If the value at $FF is $00, then we have an empty track (bad track from the original disk, and the whole track should be set to error code 21). When this happens, all the sector header info in the track descriptor block will be invalid. If we only use up to sector 16 (for tracks 31 and up), then all the info following the entry for sector 16 will be invalid. Invalid data can be anything, just ignore it. All of the sixpack files I have either created or received contain the string "AME: 1234" at the end of the track descriptor block. It is likely a "garbage" string, and can be useful in locating the descriptor blocks when manually looking over the sixpack files with a HEX editor, but it shouldn't be used in any other capacity. You also can't easily tell what track you are on, but given the track ranges covered by each file, and the sector count at the end of the descriptor block, it is possible to figure it out. Each sector is 326 bytes long (GCR encoded), and each track is 256 bytes + (# of sectors/track * 326) bytes. Track 1 would be 256 + (21 * 326) = 7102 bytes. The sector information stored in a specific interleave pattern, depending on the track we are on (unlike the entries in the descriptor block, which are stored in linear order). Note that if this was a 40 track image, the interleave pattern for the last set of tracks would apply up to track 40 instead of 35. Track Sector interleave storage pattern ----- ---------------------------------------------------- 1-17 - 0,8,16,3,11,19,6,14,1,9,17,4,12,20,7,15,2,10,18,5,13 18-24 - 0,8,16,5,13,2,10,18,7,15,4,12,1,9,17,6,14,3,11 25-30 - 0,8,16,6,14,4,12,2,10,1,9,17,7,15,5,13,3,11 31-40 - 0,8,16,7,15,6,14,5,13,4,12,3,11,2,10,1,9 The data within each sector is in two sections, and is stored *out of order*. This is partially due to the way the 1541 reads the data. The first 256 GCR bytes are read into a buffer, then the remaining 70 GCR bytes are read into an "overflow" buffer. In the Sixpack image, the last 70 bytes (of the 326) are first, then the first 256 bytes follow, for reasons left up the author of the sixpack format. You need to re-arrange the data to be in the correct order before decoding it. We actually only decode 325 bytes (from 0-324, this 325 bytes, divisible by 5), so the last byte is left out. Once decoded, we have the following information: Bytes: $000 - Data block descriptor value $07 001-100 - Normal sector info 101 - Sector checksum (EOR of the data block, from 001-100) 102-103 - "OFF" bytes ($00's), used to "fill" up the sector, to make it a multiple of 4 bytes. ZipCode disks are usually used to transfer disks which contain errors (copy-protected disks). It also is used for those disks which use unusual fastloaders such as Vorpal or Warp25, which use different low-level encoding methods. The offset for each track into its respective file can vary. Assuming that the image contains no errors, we can look at each file and calculate the offset position of where each track should be. File 1!! Offset File 2!! Offset -------- ------------- -------- ------------- Track 1 $0003 (3) Track 7 $0003 (3) Track 2 $1BC1 (7105) Track 8 $1BC1 (7105) Track 3 $377F (14207) Track 9 $377F (14207) Track 4 $533D (21309) Track 10 $533D (21309) Track 5 $6EFB (28411) Track 11 $6EFB (28411) Track 6 $8AB9 (35513) Track 12 $8AB9 (35513) File 3!! Offset File 4!! Offset -------- ------------- -------- ------------- Track 13 $0003 (3) Track 19 $0003 (3) Track 14 $1BC1 (7105) Track 20 $1935 (6453) Track 15 $377F (14207) Track 21 $3267 (12903) Track 16 $533D (21309) Track 22 $4B99 (19353) Track 17 $6EFB (28411) Track 23 $64CB (25803) Track 18 $8AB9 (35513) Track 24 $7DFD (32253) Track 25 $972F (38703) File 5!! Offset File 6!! Offset -------- ------------- -------- ------------- Track 26 $0003 (3) Track 33 $0003 (3) Track 27 $17EF (6127) Track 34 $16A9 (5801) Track 28 $2FDB (12251) Track 35 $2D4F (11599) Track 29 $47C7 (18375) Track 36 $43F5 (17397) Track 30 $5FB3 (24499) Track 37 $5A9B (23195) Track 31 $779F (30623) Track 38 $7141 (28993) Track 32 $8E45 (36421) Track 39 $87E7 (34791) Track 40 $9E8D (40589) Looking at the error codes for a normal 1541 disk, let's look at how some of the errors can be stored in the ZipCode images. The following chart is in reverse order of appearance, with the first errors being the earliest detected. Note that the description of the error may not be *completely* correct compared to how the drive DOS actually works, but serves as a reasonable explanation in understanding where the error comes from. Err# Error description and method ---- ----------------------------------------------------------------- 21 No SYNC character Before we can read any sector from a track, the drive will look for a special "sync" marker, a minimum series of 10 1-bits. If a sync marker is not found, the track is presumed bad or unformatted. The SixPack will not contain any sector data following the 256-byte header as there is no track data to store. The sector count byte in the track descriptor block will be set to zero. 20 Header block descriptor not found This applies to individual sectors where the header ID ($08, from above) isn't seen where it should be. The actual header is still read and stored, and the data should still be there. 27 Header block checksum error The checksum stored in the sector header block doesn't correspond to the checksum calculated for the header. The data block should still be there. 29 Disk ID mismatch The ID's contained in the sector header block don't match the disk master ID (from the header block of track 18/0, not the one at offset $A2/A3 of the sector data). The data block is still present. 22 Data block descriptor not found If the special value $07, preceeding the sector data isn't seen where it should be, this error is generated. The SixPack will still contain the sector data. 23 Data block checksum error This one comes from the checksum value stored after the sector data. If the checksum present doesn't match the checksum you calculate, this error is generated. The data block is still present in the SixPack. When decoding these files, and attempting to determine what errors exist, here are a few tips to work by... 1. Any errors detected in the track descriptor block (20, 27, 29) occur in linear order (sector 0,1,2,3, etc) 2. Any error detected in the data block (22, 23) is *out* of order, and follows the previously laid-out sector interleave pattern for the given track. The real strength of this format is its usefulness in transmitting error-protected and non-standard low-level fast-loaded disks. It is about the only format (next to using extended D64's) which does so. If the disk you wish to transmit has no errors, using this format would be a waste as almost *any* other format will use much less space. One caveat to this format is the unforgiving nature of the 6-pack creation utility on the C64. The one I used would generate a bad sector if it encountered a sector that was only slightly bad, but would normally read back fine on the 1541 (due to the drive's error-correcting nature).