
*** SixPack Zipcode (6-file version, 1!!xxxxx, 2!!xxxxx, etc)
*** Document revision: 1.4
*** Last updated: March 11, 2004
*** Compiler/Editor: Peter Schepers
*** Contributors/sources: Paul David Doherty,
                          Wolfgang Moser

  This is another rare form of ZipCode, spanning six files, and  hence  the
use of the name SixPack. Notice how the filename uses two  "!!"  characters
in it, versus one for the other 4-file or filepacked zipcode formats.

                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,  as  it  contains  no
compression or 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 (dec)    Hex   Binary    GCR (dec)
          ---   ------   ----------    ---   ------   ----------
           0 -   0000  - 01010 (10)     8 -   1000  - 01001 (9)
           1 -   0001  - 01011 (11)     9 -   1001  - 11001 (25)
           2 -   0010  - 10010 (18)     A -   1010  - 11010 (26)
           3 -   0011  - 10011 (19)     B -   1011  - 11011 (27)
           4 -   0100  - 01110 (14)     C -   1100  - 01101 (13)
           5 -   0101  - 01111 (15)     D -   1101  - 11101 (29)
           6 -   0110  - 10110 (22)     E -   1110  - 11110 (30)
           7 -   0111  - 10111 (23)     F -   1111  - 10101 (21)

If you look over the GCR table, there are two details that should be noted.

  1. You *cannot* combine any group of GCR nybbles into a sequence of  bits
     that contain more than 8 consecutive 1-bits. At least  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!).

     Note that some documents refer to a minimum of 12 bits  needed  for  a
     SYNC mark. This is likely why Commodore chose to use 40 bits  for  the
     standard mark, as the overkill makes it almost impossible to miss.

  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  and  start
     clocking in phantom '1' bits.

  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 beginning 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.

  The descriptor block is broken up into groups of 10 bytes. Each of  these
groups contains the header information of a sector  stored  in  the  track.
Sectors are stored in the header  in  linear  order,  but  not  necessarily
starting at sector 0. If the numbers doesn't start at  sector  0,  then  it
will go something like this: 4, 5, 6, 7, 8...16, 17, 18, 19, 20, 0,  1,  2,
3. Since this track started on sector 4, notice the wrap-around from sector
20 back to 0 and up to 3.


Here is the layout from the above sample block...

 Pos 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   garbage
      DC: A9 02 8D 00 00 00 00 00 00 00   garbage
      E6: 00 00 00 00 00 00 00 00 00 00   garbage
      F0: 00 00 00 00 00 00               garbage
      F6: 41 4D 45 3A 20 31 32 33 34      garbage "AME: 1234"
      FF: 15                              Number of valid sectors contained
                                          with this track ($15=21 dec)

  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 (SIG value)
           01 - Header checksum (EOR of bytes 02-05) (CHK value)
           02 - Sector number (SEC)
           03 - Track number (TRK)
           04 - Second byte of disk ID (ID2)
           05 - First byte of disk ID (ID1)
        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.

  Note that the numbers referred to in the "Sector Data Interleave" portion
of the table do *not* refer to actual sector numbers, but correspond to the
group position in the header descriptor block. Thus header group  0  is  at
interleave position 0, header group 1 is stored at interleave  position  8,
etc. The header and sector data must be recombined this way before decoding
the header to see what the real sector value is.

  Track    Sector Data interleave reading 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. 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).

