Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "fdd.h"
  6. #include "util.h"
  7.  
  8. //=============================================================================
  9. // ┬ёх фрээ√х тэєЄЁш ipf Їрщыр т ЇюЁьрЄх big endian
  10.  
  11. static constexpr size_t CAPS_MAXPLATFORM = 4;
  12.  
  13. static constexpr char ID_CAPS[] = "CAPS";
  14. static constexpr char ID_INFO[] = "INFO";
  15. static constexpr char ID_IMGE[] = "IMGE";
  16. static constexpr char ID_DATA[] = "DATA";
  17.  
  18. static constexpr u16 MFM_MARK_A1 = 0x4489;
  19. static constexpr u16 MFM_MARK_C2 = 0x5224;
  20.  
  21. //=============================================================================
  22. static inline u32 be2cpu(u32 x)
  23. {
  24.     return _byteswap_ulong(x);
  25. }
  26. //=============================================================================
  27. static inline u16 be2cpu(u16 x)
  28. {
  29.     return _byteswap_ushort(x);
  30. }
  31. //=============================================================================
  32. static inline u8 ReadU8(u8 *&Ptr)
  33. {
  34.     u8 x = *Ptr++;
  35.     return x;
  36. }
  37. //=============================================================================
  38. static inline u16 ReadU16(u8 *&Ptr)
  39. {
  40.     u16 x = *((u16 *)Ptr);
  41.     Ptr += sizeof(u16);
  42.     return x;
  43. }
  44. //=============================================================================
  45. static inline u32 ReadU32(u8 *&Ptr)
  46. {
  47.     u32 x = *((u32 *)Ptr);
  48.     Ptr += sizeof(u32);
  49.     return x;
  50. }
  51. //=============================================================================
  52. #pragma pack(push, 1)
  53. //=============================================================================
  54. struct TCapsId
  55. {
  56.     char Name[4];
  57.     u32 Size;
  58.     u32 Crc;
  59. };
  60. //=============================================================================
  61. enum TEncoderType : u32
  62. {
  63.     CAPS_ENCODER = 1,
  64.     SPS_ENCODER = 2
  65. };
  66. //=============================================================================
  67. // caps packed date.time format
  68. struct TCapsDateTime
  69. {
  70.     u32 date; // packed date, yyyymmdd
  71.     u32 time; // packed time, hhmmssttt
  72. };
  73. //=============================================================================
  74. // platform IDs, not about configuration, but intended use
  75. enum TPlatformId : u32
  76. {
  77.     cppidNA = 0, // invalid platform (dummy entry)
  78.     cppidAmiga,
  79.     cppidAtariST,
  80.     cppidPC,
  81.     cppidAmstradCPC,
  82.     cppidSpectrum,
  83.     cppidSamCoupe,
  84.     cppidArchimedes,
  85.     cppidC64,
  86.     cppidAtari8,
  87.     cppidLast
  88. };
  89. //=============================================================================
  90.  
  91. //=============================================================================
  92. struct TCapsInfo                // image information
  93. {
  94.     u32 type;                           // image type
  95.     TEncoderType encoder;               // image encoder ID
  96.     u32 encrev;                         // image encoder revision
  97.     u32 release;                        // release ID
  98.     u32 revision;                       // release revision ID
  99.     u32 origin;                         // original source reference
  100.     u32 mincylinder;                    // lowest cylinder number
  101.     u32 maxcylinder;                    // highest cylinder number
  102.     u32 minhead;                        // lowest head number
  103.     u32 maxhead;                        // highest head number
  104.     TCapsDateTime crdt;                 // image creation date.time
  105.     TPlatformId platform[CAPS_MAXPLATFORM];     // intended platform(s)
  106.     u32 disknum;                        // disk# for release, >= 1 if multidisk
  107.     u32 userid;                         // user id of the image creator
  108.     u32 reserved[3];                    // future use
  109. };
  110. //=============================================================================
  111. enum TDensityType : u32         // density types
  112. {
  113.     cpdenNA = 0,        // invalid density
  114.     cpdenNoise,         // cells are unformatted (random size)
  115.     cpdenAuto,          // automatic cell size, according to track size
  116.     cpdenCLAmiga,       // Copylock Amiga
  117.     cpdenCLAmiga2,      // Copylock Amiga, new
  118.     cpdenCLST,          // Copylock ST
  119.     cpdenSLAmiga,       // Speedlock Amiga
  120.     cpdenSLAmiga2,      // Speedlock Amiga, old
  121.     cpdenABAmiga,       // Adam Brierley Amiga
  122.     cpdenABAmiga2,      // Adam Brierley, density key Amiga
  123.     cpdenLast
  124. };
  125. //=============================================================================
  126. enum TSigType : u32             // signal processing used
  127. {
  128.     cpsigNA = 0, // invalid signal type
  129.     cpsig2us,  // 2us cells
  130.     cpsigLast
  131. };
  132. //=============================================================================
  133. struct TCapsImage               // track image descriptor
  134. {
  135.     u32 cylinder;               // cylinder#
  136.     u32 head;                   // head#
  137.     TDensityType dentype;       // density type
  138.     TSigType sigtype;           // signal processing type
  139.     u32 trksize;                // decoded track size, rounded
  140.     u32 startpos;               // start position, rounded
  141.     u32 startbit;               // start position on original data
  142.     u32 databits;               // decoded data size in bits
  143.     u32 gapbits;                // decoded gap size in bits
  144.     u32 trkbits;                // decoded track size in bits
  145.     u32 blkcnt;                 // number of blocks
  146.     u32 process;                // encoder prcocess
  147.     u32 flag;                   // image flags
  148.     u32 did;                    // data chunk identifier
  149.     u32 reserved[3];            // future use
  150. };
  151. //=============================================================================
  152. // data area
  153. struct TCapsData
  154. {
  155.     u32 size;  // data area size in bytes after chunk
  156.     u32 bsize; // data area size in bits
  157.     u32 dcrc;  // data area crc
  158.     u32 did;   // data chunk identifier
  159. };
  160. //=============================================================================
  161. // original meaning of some CapsBlock entries for old images
  162. struct TCapsBlockExt
  163. {
  164.     u32 blocksize;  // decoded block size, rounded
  165.     u32 gapsize;    // decoded gap size, rounded
  166. };
  167. //=============================================================================
  168. // new meaning of some CapsBlock entries for new images
  169. struct TSPSBlockExt
  170. {
  171.     u32 gapoffset;  // offset of gap stream in data area
  172.     u32 celltype;   // bitcell type
  173. };
  174. //=============================================================================
  175. // union for old or new images
  176. union TCapsBlockType
  177. {
  178.     TCapsBlockExt caps; // access old image
  179.     TSPSBlockExt sps;   // access new image
  180. //      static_assert(sizeof(sps) == sizeof(caps));
  181.         // static_assert чръюьхэўхэ т NEDOREPO
  182.         static_assert(sizeof(sps) == sizeof(caps),"sizeof(sps) == sizeof(caps");
  183. };
  184. //=============================================================================
  185. // encoder types
  186. enum TEncType : u32
  187. {
  188.     cpencNA = 0, // invalid encoder
  189.     cpencMFM,  // MFM
  190.     cpencRaw,  // no encoder used, test data only
  191.     cpencLast
  192. };
  193. //=============================================================================
  194. // CapsBlock flags
  195. union TCapsBlockFlags // ╧юЁ фюъ сшЄют√ї яюыхщ т ёЄЁєъЄєЁх ёююЄтхЄёЄтєхЄ little endian
  196. {
  197.     struct
  198.     {
  199.         u32 CAPS_BF_GP0 : 1; // bit0
  200.         u32 CAPS_BF_GP1 : 1; // bit1
  201.         u32 CAPS_BF_DMB : 1; // bit2
  202.         u32 : 29;
  203.     };
  204.     u32 Flags;
  205. };
  206. //=============================================================================
  207. // block image descriptor
  208. struct TCapsBlock
  209. {
  210.     u32 blockbits;  // decoded block size in bits
  211.     u32 gapbits;    // decoded gap size in bits
  212.     TCapsBlockType bt;  // content depending on image type
  213.     TEncType enctype;    // encoder type
  214.     TCapsBlockFlags flag;       // block flags
  215.     u32 gapvalue;   // default gap value
  216.     u32 dataoffset; // offset of data stream in data area (юЄэюёшЄхы№эю яхЁтюую caps сыюър)
  217. };
  218. //=============================================================================
  219. // gap types
  220. enum TGapType : u8
  221. {
  222.     cpgapEnd = 0, // gap stream end
  223.     cpgapCount, // gap counter
  224.     cpgapData,  // gap data pattern
  225.     cpgapLast
  226. };
  227. //=============================================================================
  228. union TGapStreamElementHdr
  229. {
  230.     struct
  231.     {
  232.         TGapType GapType : 5;
  233.         u8 GapSizeWidth : 3;
  234.     };
  235.     u8 Hdr;
  236. };
  237. //=============================================================================
  238. // data types
  239. enum TDataType : u8
  240. {
  241.     cpdatEnd = 0, // data stream end
  242.     cpdatMark,  // mark/sync
  243.     cpdatData,  // data
  244.     cpdatGap,   // gap
  245.     cpdatRaw,   // raw
  246.     cpdatFData, // flakey data
  247.     cpdatLast
  248. };
  249. //=============================================================================
  250. union TDataStreamElementHdr
  251. {
  252.     struct
  253.     {
  254.         TDataType DataType : 5;
  255.         u8 DataSizeWidth : 3;
  256.     };
  257.     u8 Hdr;
  258. };
  259. //=============================================================================
  260. #pragma pack(pop)
  261. //=============================================================================
  262. static void ReadCapsId(TCapsId *CapsId, u8 *&Ptr)
  263. {
  264.     memcpy(CapsId->Name, Ptr, 4); Ptr += 4;
  265.     CapsId->Size = be2cpu(ReadU32(Ptr));
  266.     CapsId->Crc = be2cpu(ReadU32(Ptr));
  267. }
  268. //=============================================================================
  269. static void ReadCapsDateTime(TCapsDateTime *CapsDateTime, u8 *&Ptr)
  270. {
  271.     CapsDateTime->date = be2cpu(ReadU32(Ptr));
  272.     CapsDateTime->time = be2cpu(ReadU32(Ptr));
  273. }
  274. //=============================================================================
  275. static void ReadCapsInfo(TCapsInfo *CapsInfo, u8 *&Ptr)
  276. {
  277.     CapsInfo->type = be2cpu(ReadU32(Ptr));
  278.     CapsInfo->encoder = TEncoderType(be2cpu(ReadU32(Ptr)));
  279.     CapsInfo->encrev = be2cpu(ReadU32(Ptr));
  280.     CapsInfo->release = be2cpu(ReadU32(Ptr));
  281.     CapsInfo->revision = be2cpu(ReadU32(Ptr));
  282.     CapsInfo->origin = be2cpu(ReadU32(Ptr));
  283.     CapsInfo->mincylinder = be2cpu(ReadU32(Ptr));
  284.     CapsInfo->maxcylinder = be2cpu(ReadU32(Ptr));
  285.     CapsInfo->minhead = be2cpu(ReadU32(Ptr));
  286.     CapsInfo->maxhead = be2cpu(ReadU32(Ptr));
  287.     ReadCapsDateTime(&CapsInfo->crdt, Ptr);
  288.     for(auto &v : CapsInfo->platform)
  289.     {
  290.         v = TPlatformId(be2cpu(ReadU32(Ptr)));
  291.     }
  292.     CapsInfo->disknum = be2cpu(ReadU32(Ptr));
  293.     CapsInfo->userid = be2cpu(ReadU32(Ptr));
  294.  
  295.     for(auto &v : CapsInfo->reserved)
  296.     {
  297.         v = be2cpu(ReadU32(Ptr));
  298.     }
  299. }
  300. //=============================================================================
  301. static void ReadCapsImage(TCapsImage *CapsImage, u8 *&Ptr)
  302. {
  303.     CapsImage->cylinder = be2cpu(ReadU32(Ptr));
  304.     CapsImage->head = be2cpu(ReadU32(Ptr));
  305.     CapsImage->dentype = TDensityType(be2cpu(ReadU32(Ptr)));
  306.     CapsImage->sigtype = TSigType(be2cpu(ReadU32(Ptr)));
  307.     CapsImage->trksize = be2cpu(ReadU32(Ptr));
  308.     CapsImage->startpos = be2cpu(ReadU32(Ptr));
  309.     CapsImage->startbit = be2cpu(ReadU32(Ptr));
  310.     CapsImage->databits = be2cpu(ReadU32(Ptr));
  311.     CapsImage->gapbits = be2cpu(ReadU32(Ptr));
  312.     CapsImage->trkbits = be2cpu(ReadU32(Ptr));
  313.     CapsImage->blkcnt = be2cpu(ReadU32(Ptr));
  314.     CapsImage->process = be2cpu(ReadU32(Ptr));
  315.     CapsImage->flag = be2cpu(ReadU32(Ptr));
  316.     CapsImage->did = be2cpu(ReadU32(Ptr));
  317.     for(auto &v : CapsImage->reserved)
  318.     {
  319.         v = be2cpu(ReadU32(Ptr));
  320.     }
  321. }
  322. //=============================================================================
  323. static void ReadCapsData(TCapsData *CapsData, u8 *&Ptr)
  324. {
  325.     CapsData->size = be2cpu(ReadU32(Ptr));
  326.     CapsData->bsize = be2cpu(ReadU32(Ptr));
  327.     CapsData->dcrc = be2cpu(ReadU32(Ptr));
  328.     CapsData->did = be2cpu(ReadU32(Ptr));
  329. }
  330. //=============================================================================
  331. static void ReadCapsBlockType(TCapsBlockType *CapsBlockType, TEncoderType EncoderType, u8 *&Ptr)
  332. {
  333.     switch(EncoderType)
  334.     {
  335.     case CAPS_ENCODER:
  336.         CapsBlockType->caps.blocksize = be2cpu(ReadU32(Ptr));
  337.         CapsBlockType->caps.gapsize = be2cpu(ReadU32(Ptr));
  338.         break;
  339.     case SPS_ENCODER:
  340.         CapsBlockType->sps.gapoffset = be2cpu(ReadU32(Ptr));
  341.         CapsBlockType->sps.celltype = be2cpu(ReadU32(Ptr));
  342.         break;
  343.     default:
  344.         assert(!"unknown encoder type");
  345.     }
  346. }
  347. //=============================================================================
  348. static void ReadCapsBlock(TCapsBlock *CapsBlock, TEncoderType EncoderType, u8 *&Ptr)
  349. {
  350.     CapsBlock->blockbits = be2cpu(ReadU32(Ptr));
  351.     CapsBlock->gapbits = be2cpu(ReadU32(Ptr));
  352.     ReadCapsBlockType(&CapsBlock->bt, EncoderType, Ptr);
  353.     CapsBlock->enctype = TEncType(be2cpu(ReadU32(Ptr)));
  354.     CapsBlock->flag.Flags = be2cpu(ReadU32(Ptr));
  355.     CapsBlock->gapvalue = be2cpu(ReadU32(Ptr));
  356.     CapsBlock->dataoffset = be2cpu(ReadU32(Ptr));
  357. }
  358. //=============================================================================
  359. static void ReadGapHdr(TGapStreamElementHdr *GapStreamElementHdr, u8 *&Ptr)
  360. {
  361.     GapStreamElementHdr->Hdr = *Ptr++;
  362. }
  363. //=============================================================================
  364. static u32 ReadVarUint(unsigned n, u8 *&Ptr)
  365. {
  366.     u32 v = 0;
  367.     for(unsigned i = 0; i < n; i++)
  368.     {
  369.         v |= unsigned(*Ptr) << (n - i - 1) * 8;
  370.         Ptr++;
  371.     }
  372.  
  373.     return v;
  374. }
  375. //=============================================================================
  376. static void ReadDataHdr(TDataStreamElementHdr *DataStreamElementHdr, u8 *&Ptr)
  377. {
  378.     DataStreamElementHdr->Hdr = *Ptr++;
  379. }
  380. //=============================================================================
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389. //=============================================================================
  390. int FDD::read_ipf()
  391. {
  392.     u8 *Gptr = snbuf;
  393.  
  394.     u8 *Ptr = Gptr;
  395.     TCapsId CapsId;
  396.     ReadCapsId(&CapsId, Ptr);
  397.  
  398.     Gptr += CapsId.Size;
  399.     Ptr = Gptr;
  400.  
  401.     if(memcmp(CapsId.Name, ID_CAPS, sizeof(CapsId.Name)) != 0)
  402.     {
  403.         return 0;
  404.     }
  405.  
  406.     ReadCapsId(&CapsId, Ptr);
  407.     if(memcmp(CapsId.Name, ID_INFO, sizeof(CapsId.Name)) != 0)
  408.     {
  409.         return 0;
  410.     }
  411.  
  412.     TCapsInfo CapsInfo;
  413.     ReadCapsInfo(&CapsInfo, Ptr);
  414.  
  415.     Gptr += CapsId.Size;
  416.     Ptr = Gptr;
  417.     u8 *ImgeStart = Gptr; // ═рўрыю ьрёёштр чряшёхщ IMGE
  418.  
  419.     if(CapsInfo.maxcylinder >= MAX_CYLS)
  420.     {
  421.         err_printf("cylinders (%u) > MAX_CYLS(%d)", cyls, MAX_CYLS);
  422.         return 0;
  423.     }
  424.  
  425.     if(CapsInfo.maxhead >= 2)
  426.     {
  427.         err_printf("sides (%u) > 2", sides);
  428.         return 0;
  429.     }
  430.  
  431.     cyls = CapsInfo.maxcylinder + 1;
  432.     sides = CapsInfo.maxhead + 1;
  433.  
  434.     size_t mem = 0;
  435.     const unsigned bitmap_len = (unsigned(MAX_TRACK_LEN + 7U)) >> 3;
  436.  
  437.     mem += (MAX_CYLS - cyls) * sides * (MAX_TRACK_LEN + bitmap_len); // ─юсртър фы  тючьюцэюёЄш ЇюЁьрЄшЁютрэш  эр MAX_CYLS фюЁюцхъ
  438.  
  439.     rawsize = align_by(mem, 4096U);
  440.     rawdata = (unsigned char*)VirtualAlloc(nullptr, rawsize, MEM_COMMIT, PAGE_READWRITE);
  441.     u8 *dst = rawdata;
  442.  
  443.     auto Ncyls{ CapsInfo.maxcylinder - CapsInfo.mincylinder + 1 };
  444.     auto Nheads{ CapsInfo.maxhead - CapsInfo.minhead + 1 };
  445.  
  446.     u8 *DataStart2 = Gptr + (Ncyls * Nheads)*(sizeof(TCapsId) + sizeof(TCapsImage));
  447.  
  448.     // ═хшёяюы№чєхь√х ЄЁ¤ъш т эрўрых фшёър
  449.     for(unsigned c = 0; c < CapsInfo.mincylinder; c++)
  450.     {
  451.         for(unsigned h = 0; h < sides; h++)
  452.         {
  453.             trklen[c][h] = MAX_TRACK_LEN;
  454.             trkd[c][h] = dst;
  455.             dst += MAX_TRACK_LEN;
  456.  
  457.             trki[c][h] = dst;
  458.             dst += bitmap_len;
  459.         }
  460.     }
  461.  
  462.     for(unsigned c = CapsInfo.mincylinder; c <= CapsInfo.maxcylinder; c++)
  463.     {
  464.         for(unsigned h = CapsInfo.minhead; h <= CapsInfo.maxhead; h++)
  465.         {
  466.             ReadCapsId(&CapsId, Ptr);
  467.             assert(memcmp(CapsId.Name, ID_IMGE, sizeof(CapsId.Name)) == 0);
  468.  
  469.             TCapsImage CapsImage;
  470.             ReadCapsImage(&CapsImage, Ptr);
  471.             assert(CapsImage.cylinder == c && CapsImage.head == h);
  472.  
  473.             Gptr += CapsId.Size;
  474.             Ptr = Gptr;
  475.         }
  476.     }
  477.  
  478.     u8 *DataStart = Gptr; // ═рўрыю ьрёёштр чряшёхщ DATA
  479.     assert(DataStart == DataStart2);
  480.  
  481.     for(unsigned c = CapsInfo.mincylinder; c <= CapsInfo.maxcylinder; c++)
  482.     {
  483.         for(unsigned h = CapsInfo.minhead; h <= CapsInfo.maxhead; h++)
  484.         {
  485.             ReadCapsId(&CapsId, Ptr);
  486.             assert(memcmp(CapsId.Name, ID_DATA, sizeof(CapsId.Name)) == 0);
  487.  
  488.             TCapsData CapsData; // ┴ыюъш яхЁхьхээющ фышэ√
  489.             ReadCapsData(&CapsData, Ptr);
  490.  
  491.             u8 *PtrCapsBlock = Ptr;
  492.             Gptr += CapsId.Size + CapsData.size;
  493.  
  494.             Ptr = ImgeStart + (sizeof(TCapsId) + sizeof(TCapsImage)) * (CapsData.did - 1);
  495.  
  496.             ReadCapsId(&CapsId, Ptr);
  497.             assert(memcmp(CapsId.Name, ID_IMGE, sizeof(CapsId.Name)) == 0);
  498.  
  499.             TCapsImage CapsImage;
  500.             ReadCapsImage(&CapsImage, Ptr);
  501.             assert(CapsImage.cylinder == c && CapsImage.head == h);
  502.             assert(CapsImage.did == CapsData.did);
  503.  
  504. //            assert(CapsImage.trksize % 2 == 0);
  505.             unsigned sz = min(unsigned(CapsImage.trksize / 2), unsigned(MAX_TRACK_LEN)); // ╨рчьхЁ т сшЄют√ї  ўхщърї / 8
  506.             trklen[c][h] = sz;
  507.             trkd[c][h] = dst;
  508.  
  509.             u8 *dsti = dst + sz;
  510.             trki[c][h] = dsti;
  511.  
  512.             Ptr = PtrCapsBlock;
  513.  
  514.             u32 FixedGapSize = 0;
  515.  
  516.             // ╨рёўхЄ ёєььрЁэюую ЁрчьхЁр тёхї ЇшъёшЁютрээ√ї GAP'ют
  517.             for(unsigned i = 0; i < CapsImage.blkcnt; i++)
  518.             {
  519.                 TCapsBlock CapsBlock;
  520.                 ReadCapsBlock(&CapsBlock, CapsInfo.encoder, Ptr);
  521.                 u8 *Optr = Ptr;
  522.  
  523.                 Ptr = PtrCapsBlock + CapsBlock.bt.sps.gapoffset;
  524.  
  525.                 auto GalcGapSize = [&Ptr, &FixedGapSize]()
  526.                 {
  527.                     bool IsEnd = false;
  528.                     u32 Count = 0;
  529.                     do
  530.                     {
  531.                         TGapStreamElementHdr GapHdr;
  532.                         ReadGapHdr(&GapHdr, Ptr);
  533.  
  534.                         IsEnd = (GapHdr.GapSizeWidth == 0 && GapHdr.GapType == cpgapEnd);
  535.                         if(GapHdr.GapSizeWidth != 0)
  536.                         {
  537.                             u32 Size = ReadVarUint(GapHdr.GapSizeWidth, Ptr); // ┬хышўшэр т сшЄрї
  538.                             Size = (Size + 7) / 8; // ┬хышўшэр т срщЄрї
  539.                             switch(GapHdr.GapType)
  540.                             {
  541.                             case cpgapCount:
  542.                                 Count = Size;
  543.                                 break;
  544.                             case cpgapData:
  545.                             {
  546.                                 FixedGapSize += Count * Size;
  547.  
  548.                                 Ptr += Size;
  549.                                 break;
  550.                             }
  551.                             }
  552.                         }
  553.                     } while(!IsEnd);
  554.                 };
  555.  
  556.                 if(CapsBlock.flag.CAPS_BF_GP0) // Fw gap
  557.                 {
  558.                     GalcGapSize();
  559.                 }
  560.  
  561.                 if(CapsBlock.flag.CAPS_BF_GP1) // Bw gap
  562.                 {
  563.                     GalcGapSize();
  564.                 }
  565.  
  566.                 Ptr = Optr;
  567.             }
  568.  
  569.  
  570.             // ╧ючшЎш  т сшЄют√ї  ўхщърї / 8, ъюЁЁхъЎш  ъ ёЄрэфрЁЄэющ фышэх ЄЁ¤ър
  571.             // (ьэюушх ipf ╘рщы√ шьх■Є фышэє ЄЁ¤ър > 100000 сшЄют√ї  ўххъ)
  572.             // тшфшью юсЁрч√ ёэшьрыш эр фшёъютюфх ё чрэшцхээющ ёъюЁюёЄ№■ тЁр∙хэш  °яшэфхы 
  573.             // (фшёъютюф√ юЄ +3 эх шьх■Є ътрЁЎхтющ ёЄрсшышчрЎшш ёъюЁюёЄш тЁр∙хэш , ш шёяюы№чє■Є фтшурЄхы№ ё ярёёшъюь,
  574.             // р эх ёшэїЁюээ√щ ьэюуюяюы■ёэ√щ фтшурЄхы№ ё яЁ ь√ь яЁштюфюь)
  575.             // http://www.cpcwiki.eu/index.php/Amstrad_FDD_part (эр +3 яЁшьхэ ышё№ рэрыюушўэ√х фшёъютюф√)
  576.             u32 RealGapBits = MAX_TRACK_LEN * 16 - CapsImage.databits;
  577.             assert(RealGapBits >= FixedGapSize * 16);
  578.             u32 AvailGapBits = RealGapBits - FixedGapSize * 16;
  579.             u32 FlexGapBits = CapsImage.gapbits - FixedGapSize * 16;
  580.             u32 StartPos = (FlexGapBits != 0) ? (CapsImage.startbit * AvailGapBits) / (16 * FlexGapBits) : 0;
  581.             if(StartPos < 13)
  582.             {
  583.                 StartPos = 13; // 4E + 12(00)
  584.             }
  585.  
  586.             dst += StartPos;
  587.  
  588.             Ptr = PtrCapsBlock;
  589.  
  590.             for(unsigned i = 0; i < CapsImage.blkcnt; i++)
  591.             {
  592.                 TCapsBlock CapsBlock;
  593.                 ReadCapsBlock(&CapsBlock, CapsInfo.encoder, Ptr);
  594.                 u8 *Optr = Ptr;
  595.  
  596.                 unsigned GapBitsRemaining = CapsBlock.gapbits / 2; // ▌Єю эх сшЄ√, р MFM  ўхщъш (шї т 2 Ёрчр сюы№°х ўхь сшЄют)
  597.  
  598.                 assert(CapsInfo.encoder == SPS_ENCODER);
  599.  
  600.  
  601.                 Ptr = PtrCapsBlock + CapsBlock.dataoffset;
  602.  
  603.                 bool IsEnd = false;
  604.                 do
  605.                 {
  606.                     TDataStreamElementHdr DataHdr;
  607.                     ReadDataHdr(&DataHdr, Ptr);
  608.  
  609.                     IsEnd = (DataHdr.DataSizeWidth == 0 && DataHdr.DataType == cpdatEnd);
  610.                     if(DataHdr.DataSizeWidth != 0)
  611.                     {
  612.                         u32 Size = ReadVarUint(DataHdr.DataSizeWidth, Ptr);
  613.                         if(CapsBlock.flag.CAPS_BF_DMB) // ЁрчьхЁ фрээ√ї т сшЄрї
  614.                         {
  615. //                            assert(Size % 8 == 0);
  616.                             Size = (Size + 7) / 8;
  617.                         }
  618.                         switch(DataHdr.DataType)
  619.                         {
  620.                         case cpdatMark: // ╤шэїЁюьхЄъш чръюфшЁютрээ√х яю яЁртшырь MFM
  621.                         {
  622.                             u8 *Optr2 = Ptr;
  623.                             assert(Size % 2 == 0);
  624.                             for(unsigned j = 0; j < Size / 2; j++)
  625.                             {
  626.                                 u16 Mark = be2cpu(ReadU16(Ptr));
  627.                                 assert(dst + 1 - trkd[c][h] <= trklen[c][h]);
  628.                                 unsigned pos = unsigned(dst - trkd[c][h]);
  629.                                 switch(Mark)
  630.                                 {
  631.                                 case MFM_MARK_A1: // A1
  632.                                     *dst++ = 0xA1;
  633.                                     set_i(c, h, pos);
  634.                                     break;
  635.                                 case MFM_MARK_C2: // C2
  636.                                     *dst++ = 0xC2;
  637.                                     set_i(c, h, pos);
  638.                                     break;
  639.                                 default:
  640.                                     assert(!"unknown mark");
  641.                                 }
  642.                             }
  643.                             Ptr = Optr2;
  644.                             break;
  645.                         }
  646.                         case cpdatData: // ─рээ√х (т тшфх фхъюфшЁютрэ√ї срщЄют)
  647.                         case cpdatGap: // ╟ряюыэшЄхыш gap (т тшфх фхъюфшЁютрэ√ї срщЄют)
  648.                             assert(dst + Size - trkd[c][h] <= trklen[c][h]);
  649.                             memcpy(dst, Ptr, Size);
  650.                             dst += Size;
  651.                             break;
  652.                         default:
  653.                             assert(!"invalid data type");
  654.                         }
  655.                         Ptr += Size;
  656.                     }
  657.                 } while(!IsEnd);
  658.  
  659.                 Ptr = PtrCapsBlock + CapsBlock.bt.sps.gapoffset;
  660.  
  661.                 auto ProcessGap = [&Ptr, &dst, &GapBitsRemaining, StartPos, c, h, i, this]()
  662.                 {
  663.                     bool IsEnd = false;
  664.                     u32 Count = 0;
  665.                     u8 *GapPtr = nullptr;
  666.                     u32 GapDataSize = 0;
  667.                     do
  668.                     {
  669.                         TGapStreamElementHdr GapHdr;
  670.                         ReadGapHdr(&GapHdr, Ptr);
  671.  
  672.                         IsEnd = (GapHdr.GapSizeWidth == 0 && GapHdr.GapType == cpgapEnd);
  673.                         if(GapHdr.GapSizeWidth != 0)
  674.                         {
  675.                             u32 Size = ReadVarUint(GapHdr.GapSizeWidth, Ptr); // ┬хышўшэр т сшЄрї
  676.                             Size = (Size + 7) / 8; // ┬хышўшэр т срщЄрї
  677.                             switch(GapHdr.GapType)
  678.                             {
  679.                             case cpgapCount:
  680.                                 Count = Size;
  681.                                 break;
  682.                             case cpgapData:
  683.                             {
  684. //                                printf("c=%u,h=%u,i=%u,o=0x%X\n", c, h, i, unsigned(dst - trkd[c][h] + 0x13));
  685.  
  686.                                 if(Count == 0) // GAP яхЁхьхээющ фышэ√
  687.                                 {
  688.                                     if(dst - trkd[c][h] >= trklen[c][h]) // ═рўрыю ЄЁ¤ър
  689.                                     {
  690.                                         GapPtr = Ptr;
  691.                                         GapDataSize = Size;
  692.                                     }
  693.                                     else // ╩юэхЎ ЄЁ¤ър
  694.                                     {
  695.                                         Count = min(GapBitsRemaining / 8, unsigned(trklen[c][h] - (dst - trkd[c][h])));
  696.                                     }
  697.                                 }
  698.  
  699.                                 if(dst - trkd[c][h] < trklen[c][h])
  700.                                 {
  701.                                     while(Count)
  702.                                     {
  703.                                         assert(dst - trkd[c][h] < trklen[c][h]);
  704.                                         memcpy(dst, Ptr, Size);
  705.                                         dst += Size;
  706.                                         GapBitsRemaining -= Size * 8;
  707.                                         Count--;
  708.                                     }
  709.                                 }
  710.                                 else if(Count != 0)
  711.                                 {
  712.                                     assert(StartPos >= Count * Size);
  713.                                     dst = trkd[c][h] + StartPos - Count * Size;
  714.  
  715.                                     u32 CountOld = Count;
  716.                                     while(Count) // GAP ЇшъёшЁютрээющ фышэ√ яхЁхф C2C2C2FC
  717.                                     {
  718.                                         assert(dst - trkd[c][h] < trklen[c][h]);
  719.                                         memcpy(dst, Ptr, Size);
  720.                                         dst += Size;
  721.                                         GapBitsRemaining -= Size * 8;
  722.                                         Count--;
  723.                                     }
  724.  
  725.                                     if(GapPtr) // GAP яхЁхьхээющ фышэ√ т эрўрых ЄЁ¤ър
  726.                                     {
  727.                                         dst = trkd[c][h];
  728.                                         Count = StartPos - CountOld * Size;
  729.  
  730.                                         while(Count)
  731.                                         {
  732.                                             assert(dst - trkd[c][h] < trklen[c][h]);
  733.                                             memcpy(dst, GapPtr, GapDataSize);
  734.                                             dst += GapDataSize;
  735.                                             GapBitsRemaining -= GapDataSize * 8;
  736.                                             Count--;
  737.                                         }
  738.  
  739.                                         GapPtr = nullptr;
  740.                                     }
  741.                                 }
  742.                                 Ptr += Size;
  743.                                 break;
  744.                             }
  745.                             }
  746.                         }
  747.                     } while(!IsEnd);
  748.                 };
  749.  
  750.                 if(CapsBlock.flag.CAPS_BF_GP0) // Fw gap
  751.                 {
  752.                     ProcessGap();
  753.                 }
  754.  
  755.                 if(CapsBlock.flag.CAPS_BF_GP1) // Bw gap
  756.                 {
  757.                     ProcessGap();
  758.                 }
  759.  
  760. //                assert(GapBitsRemaining == 0);
  761.                 Ptr = Optr;
  762.             }
  763.  
  764.             dst += sz - (dst - trkd[c][h]);
  765.             assert(dst - trkd[c][h] == sz);
  766.             dst += (unsigned(sz + 7)) >> 3;
  767.             Ptr = Gptr;
  768.         }
  769.     }
  770.  
  771.     // ═хшёяюы№чєхь√х ЄЁ¤ъш т ъюэЎх фшёър
  772.     for(unsigned c = CapsInfo.maxcylinder + 1; c < MAX_CYLS; c++)
  773.     {
  774.         for(unsigned h = 0; h < sides; h++)
  775.         {
  776.             trklen[c][h] = MAX_TRACK_LEN;
  777.             trkd[c][h] = dst;
  778.             dst += MAX_TRACK_LEN;
  779.  
  780.             trki[c][h] = dst;
  781.             dst += bitmap_len;
  782.         }
  783.     }
  784.  
  785.     return 1;
  786. }
  787. //=============================================================================
  788.  
  789.