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