1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /*************************************************************************
4
5 Hard disk emulation: Format implementation
6 ------------------------------------------
7
8 This is the format implementation for MFM hard disks, similar to the
9 modular format concept of floppy drives in MAME/MESS.
10
11 The base class is mfmhd_image_format_t; it contains some methods for
12 encoding and decoding MFM. Although MFM hard disks should also be able to
13 manage FM recording, we do not plan for FM recording here.
14
15 The encode/decode methods rely on a parameter "encoding";
16 see imagedev/mfmhd.c for a discussion. Essentially, it determines whether
17 data are read bitwise or bytewise, and whether clock bits are separated
18 or interleaved.
19
20 The base class is abstract; you must create a subclass to use it. This
21 file delivers one subclass called mfmhd_generic_format.
22
23 In order to use this format, you must pass the creator identifier to the
24 macro MCFG_MFM_HARDDISK_CONN_ADD. See emu/bus/ti99_peb/hfdc.c for an
25 example.
26
27
28 Generic MFM format
29 ------------------
30 The heart of this class are the methods load and save. They are designed
31 to read sector data from a CHD file and reconstruct the track image (load),
32 or to take a track image, isolate the sector data, and store them
33 into the CHD (save).
34
35 Rebuilding the track image means to create sector headers, allocate gaps,
36 add sync areas, and CRC values. Also, the sectors must be arranged
37 according to the "interleave" parameter and the "skew" parameters for
38 heads and cylinders. While the skews are commonly set to 0, the interleave
39 is often used to fine-tune the transfer speed between the drive hardware
40 and the host system.
41
42 Also, the format allows for two header setups.
43 a) PC-AT-compatible header: four bytes long (ident, cylinder, head, sector);
44 the sector size is always 512 bytes.
45 b) Custom headers: five bytes long (..., sector size). The custom headers
46 are used in non-PC systems.
47
48 ECC: While floppy drives make use of a CRC field to check the data integrity,
49 hard disks use an ECC (error correcting code). The ECC length is 4 bytes
50 or longer, depending on the desired correction capability. The ECC length
51 can also be specified for this format.
52
53 However, for this version, we do not support ECC computation, but instead
54 we use CRC. This is indicated by setting the "ECC length" parameter to -1.
55
56 Format autodetect
57 -----------------
58 While formatting a hard disk, format parameters are likely to change, so
59 we have to find out about the new layout and store the metadata into the
60 CHD if they were modified.
61
62 This is done in the save method. This method does not only retrieve the
63 sector contents but also counts the gap bytes and sync bytes so that
64 they can be stored in the CHD.
65
66 - Interleave detection: save counts the number of sectors between sector
67 number n and sector number n+1.
68
69 - Skew detection: Skew is determined by three tracks: (cyl,head)=
70 (0,0), (1,0), and (0,1). For this purpose we use the m_secnumber list.
71
72 - Header length is detemined by the first sector on (0,0). This is done
73 by checking the header against the following two CRC bytes. If they
74 match for 4 bytes, we have an AT-style header, else a custom header.
75
76 - Gap and sync lengths are determined by the first track (0,0). They are
77 actually not expected to change, unless they are undefined before first
78 use, or the controller or its driver changes. We assume that track
79 (0,0) is actually rewritten during reformatting.
80
81 Since write precompensation and reduced write current cannot be seen
82 on the track image directly, those two values have to be set by the
83 hard disk device itseltf.
84
85 Inhibit autodetect
86 ------------------
87 In case we do not want the format to detect the layout but want to ensure
88 an immutable format, the save_param method may be overwritten to return
89 false for all or a particular group of parameters. The generic format
90 offers a save_param method which always returns true.
91
92 The effect of inhibiting the autodetection is that the layout parameters
93 as found on the CHD are used if available; otherwise defaults are used.
94
95 Defaults
96 --------
97 The generic format defines a method get_default which returns safe values
98 for layout parameters. It can be overwritten for specific formats.
99
100 Debugging
101 ---------
102 There is a set of debug flags (starting with TRACE_) that can be set to 1;
103 after recompiling you will get additional output. Since this class is not
104 a descendant of device_t we do not have a tag for output; for a better
105 overview in the logfile the hard disk device passes its tag to the base
106 class.
107
108
109 TODO
110 ----
111 - Add ECC computation
112
113
114 Michael Zapf
115 August 2015
116
117 **************************************************************************/
118
119 #include "mfm_hd.h"
120 #include "imageutl.h"
121
122 #define TRACE_RWTRACK 0
123 #define TRACE_LAYOUT 0
124 #define TRACE_IMAGE 0
125 #define TRACE_DETAIL 0
126 #define TRACE_FORMAT 0
127
128 /*
129 Accept the new layout parameters and reset the sector number fields
130 used for skew calculation.
131 */
set_layout_params(mfmhd_layout_params param)132 void mfmhd_image_format_t::set_layout_params(mfmhd_layout_params param)
133 {
134 m_param = m_param_old = param;
135 m_secnumber[0] = m_secnumber[1] = m_secnumber[2] = -1;
136 }
137
138 /*
139 Encode some value with data-type clock bits.
140 */
mfm_encode(uint16_t * trackimage,int & position,uint8_t byte,int count)141 void mfmhd_image_format_t::mfm_encode(uint16_t* trackimage, int& position, uint8_t byte, int count)
142 {
143 mfm_encode_mask(trackimage, position, byte, count, 0x00);
144 }
145
146 /*
147 Encode an A1 value with mark-type clock bits.
148 */
mfm_encode_a1(uint16_t * trackimage,int & position)149 void mfmhd_image_format_t::mfm_encode_a1(uint16_t* trackimage, int& position)
150 {
151 m_current_crc = 0xffff;
152 mfm_encode_mask(trackimage, position, 0xa1, 1, 0x04);
153 }
154
155 /*
156 Encode a byte value with a given clock bit mask. Used by both mfm_encode
157 and mfm_encode_a1 methods.
158 */
mfm_encode_mask(uint16_t * trackimage,int & position,uint8_t byte,int count,int mask)159 void mfmhd_image_format_t::mfm_encode_mask(uint16_t* trackimage, int& position, uint8_t byte, int count, int mask)
160 {
161 uint16_t encclock = 0;
162 uint16_t encdata = 0;
163 uint8_t thisbyte = byte;
164 bool mark = (mask != 0x00);
165
166 m_current_crc = ccitt_crc16_one(m_current_crc, byte);
167
168 for (int i=0; i < 8; i++)
169 {
170 encdata <<= 1;
171 encclock <<= 1;
172
173 if (m_param.encoding == MFM_BITS || m_param.encoding == MFM_BYTE)
174 {
175 // skip one position for later interleaving
176 encdata <<= 1;
177 encclock <<= 1;
178 }
179
180 if (thisbyte & 0x80)
181 {
182 // Encoding 1 => 01
183 encdata |= 1;
184 m_lastbit = true;
185 }
186 else
187 {
188 // Encoding 0 => x0
189 // If the bit in the mask is set, suppress the clock bit
190 // Also, if we use the simplified encoding, don't set the clock bits
191 if (m_lastbit == false && m_param.encoding != SEPARATED_SIMPLE && (mask & 0x80) == 0) encclock |= 1;
192 m_lastbit = false;
193 }
194 mask <<= 1;
195 // For simplified encoding, set all clock bits to indicate a mark
196 if (m_param.encoding == SEPARATED_SIMPLE && mark) encclock |= 1;
197 thisbyte <<= 1;
198 }
199
200 if (m_param.encoding == MFM_BITS || m_param.encoding == MFM_BYTE)
201 encclock <<= 1;
202 else
203 encclock <<= 8;
204
205 trackimage[position++] = (encclock | encdata);
206
207 // When we write the byte multiple times, check whether the next encoding
208 // differs from the previous because of the last bit
209
210 if (m_param.encoding == MFM_BITS || m_param.encoding == MFM_BYTE)
211 {
212 encclock &= 0x7fff;
213 if ((byte & 0x80)==0 && m_lastbit==false) encclock |= 0x8000;
214 }
215
216 for (int j=1; j < count; j++)
217 {
218 trackimage[position++] = (encclock | encdata);
219 m_current_crc = ccitt_crc16_one(m_current_crc, byte);
220 }
221 }
222
223 /*
224 Decode an MFM cell pattern into a byte value.
225 Clock bits and data bits are assumed to be interleaved (cdcdcdcdcdcdcdcd);
226 the 8 data bits are returned.
227 */
mfm_decode(uint16_t raw)228 uint8_t mfmhd_image_format_t::mfm_decode(uint16_t raw)
229 {
230 unsigned int value = 0;
231
232 for (int i=0; i < 8; i++)
233 {
234 value <<= 1;
235
236 value |= (raw & 0x4000);
237 raw <<= 2;
238 }
239 return (value >> 14) & 0xff;
240 }
241
242 /*
243 For debugging. Outputs the byte array in a xxd-like way.
244 */
showtrack(uint16_t * enctrack,int length)245 void mfmhd_image_format_t::showtrack(uint16_t* enctrack, int length)
246 {
247 for (int i=0; i < length; i+=16)
248 {
249 osd_printf_verbose("%07x: ", i);
250 for (int j=0; j < 16; j++)
251 {
252 osd_printf_verbose("%04x ", enctrack[i+j]);
253 }
254 osd_printf_verbose(" ");
255 osd_printf_verbose("\n");
256 }
257 }
258
259 // ======================================================================
260 // Generic MFM HD format
261 // ======================================================================
262
263 const mfmhd_format_type MFMHD_GEN_FORMAT = &mfmhd_image_format_creator<mfmhd_generic_format>;
264
265 /*
266 Calculate the ident byte from the cylinder. The specification does not
267 define idents beyond cylinder 1023, but formatting programs seem to
268 continue with 0xfd for cylinders between 1024 and 2047.
269 */
cylinder_to_ident(int cylinder)270 uint8_t mfmhd_generic_format::cylinder_to_ident(int cylinder)
271 {
272 if (cylinder < 256) return 0xfe;
273 if (cylinder < 512) return 0xff;
274 if (cylinder < 768) return 0xfc;
275 return 0xfd;
276 }
277
278 /*
279 Returns the linear sector number, given the CHS data.
280
281 C,H,S
282 | 0,0,0 | 0,0,1 | 0,0,2 | ...
283 | 0,1,0 | 0,1,1 | 0,1,2 | ...
284 ...
285 | 1,0,0 | ...
286 ...
287 */
chs_to_lba(int cylinder,int head,int sector)288 int mfmhd_generic_format::chs_to_lba(int cylinder, int head, int sector)
289 {
290 if ((cylinder < m_param.cylinders) && (head < m_param.heads) && (sector < m_param.sectors_per_track))
291 {
292 return (cylinder * m_param.heads + head) * m_param.sectors_per_track + sector;
293 }
294 else return -1;
295 }
296
load(chd_file * chdfile,uint16_t * trackimage,int tracksize,int cylinder,int head)297 chd_error mfmhd_generic_format::load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head)
298 {
299 chd_error state = CHDERR_NONE;
300 uint8_t sector_content[16384];
301
302 int sectorcount = m_param.sectors_per_track;
303 int size = m_param.sector_size;
304 int position = 0; // will be incremented by each encode call
305 int sec_number = 0;
306 int identfield = 0;
307 int cylfield = 0;
308 int headfield = 0;
309 int sizefield = (size >> 7)-1;
310
311 // If we don't have interleave data in the CHD, take a default
312 if (m_param.interleave==0)
313 {
314 m_param.interleave = get_default(MFMHD_IL);
315 m_param.cylskew = get_default(MFMHD_CSKEW);
316 m_param.headskew = get_default(MFMHD_HSKEW);
317 }
318
319 int sec_il_start = (m_param.cylskew * cylinder + m_param.headskew * head) % sectorcount;
320 int delta = (sectorcount + m_param.interleave-1) / m_param.interleave;
321
322 if (TRACE_RWTRACK) osd_printf_verbose("%s: Load track (c=%d,h=%d) from CHD, interleave=%d, cylskew=%d, headskew=%d\n", tag(), cylinder, head, m_param.interleave, m_param.cylskew, m_param.headskew);
323
324 m_lastbit = false;
325
326 if (m_param.sync==0)
327 {
328 m_param.gap1 = get_default(MFMHD_GAP1);
329 m_param.gap2 = get_default(MFMHD_GAP2);
330 m_param.gap3 = get_default(MFMHD_GAP3);
331 m_param.sync = get_default(MFMHD_SYNC);
332 m_param.headerlen = get_default(MFMHD_HLEN);
333 m_param.ecctype = get_default(MFMHD_ECC);
334 }
335
336 // Gap 1
337 mfm_encode(trackimage, position, 0x4e, m_param.gap1);
338
339 if (TRACE_LAYOUT) osd_printf_verbose("%s: cyl=%d head=%d: sector sequence = ", tag(), cylinder, head);
340
341 sec_number = sec_il_start;
342 for (int sector = 0; sector < sectorcount; sector++)
343 {
344 if (TRACE_LAYOUT) osd_printf_verbose("%02d ", sec_number);
345
346 // Sync gap
347 mfm_encode(trackimage, position, 0x00, m_param.sync);
348
349 // Write IDAM
350 mfm_encode_a1(trackimage, position);
351
352 // Write header
353 identfield = cylinder_to_ident(cylinder);
354 cylfield = cylinder & 0xff;
355 headfield = head & 0x0f;
356 if (m_param.headerlen==5)
357 headfield |= ((cylinder & 0x700)>>4);
358
359 mfm_encode(trackimage, position, identfield);
360 mfm_encode(trackimage, position, cylfield);
361 mfm_encode(trackimage, position, headfield);
362 mfm_encode(trackimage, position, sec_number);
363 if (m_param.headerlen==5)
364 mfm_encode(trackimage, position, sizefield);
365
366 // Write CRC for header.
367 int crc = m_current_crc;
368 mfm_encode(trackimage, position, (crc >> 8) & 0xff);
369 mfm_encode(trackimage, position, crc & 0xff);
370
371 // Gap 2
372 mfm_encode(trackimage, position, 0x4e, m_param.gap2);
373
374 // Sync
375 mfm_encode(trackimage, position, 0x00, m_param.sync);
376
377 // Write DAM
378 mfm_encode_a1(trackimage, position);
379 mfm_encode(trackimage, position, 0xfb);
380
381 // Get sector content from CHD
382 int lbaposition = chs_to_lba(cylinder, head, sec_number);
383 if (lbaposition>=0)
384 {
385 chd_error state = chdfile->read_units(lbaposition, sector_content);
386 if (state != CHDERR_NONE) break;
387 }
388 else
389 {
390 osd_printf_verbose("%s: Invalid CHS data (%d,%d,%d); not loading from CHD\n", tag(), cylinder, head, sector);
391 }
392
393 for (int i=0; i < size; i++)
394 mfm_encode(trackimage, position, sector_content[i]);
395
396 // Write CRC for content.
397 crc = m_current_crc;
398 mfm_encode(trackimage, position, (crc >> 8) & 0xff);
399 mfm_encode(trackimage, position, crc & 0xff);
400
401 // Gap 3
402 mfm_encode(trackimage, position, 0x00, 3);
403 mfm_encode(trackimage, position, 0x4e, m_param.gap3-3);
404
405 // Calculate next sector number
406 sec_number += delta;
407 if (sec_number >= sectorcount)
408 {
409 sec_il_start = (sec_il_start+1) % delta;
410 sec_number = sec_il_start;
411 }
412 }
413 if (TRACE_LAYOUT) osd_printf_verbose("\n");
414
415 // Gap 4
416 if (state == CHDERR_NONE)
417 {
418 // Fill the rest with 0x4e
419 mfm_encode(trackimage, position, 0x4e, tracksize-position);
420 if (TRACE_IMAGE) showtrack(trackimage, tracksize);
421 }
422 return state;
423 }
424
425 /*
426 State names for analyzing the track image.
427 */
428 enum
429 {
430 SEARCH_A1=0,
431 FOUND_A1,
432 DAM_FOUND,
433 CHECK_CRC
434 };
435
save(chd_file * chdfile,uint16_t * trackimage,int tracksize,int current_cylinder,int current_head)436 chd_error mfmhd_generic_format::save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int current_cylinder, int current_head)
437 {
438 if (TRACE_RWTRACK) osd_printf_verbose("%s: write back (c=%d,h=%d) to CHD\n", tag(), current_cylinder, current_head);
439
440 uint8_t buffer[16384]; // for header or sector content
441
442 int bytepos = 0;
443 int state = SEARCH_A1;
444 int count = 0;
445 int pos = 0;
446 uint16_t crc = 0;
447 uint8_t byte;
448 bool search_header = true;
449
450 int ident = 0;
451 int cylinder = 0;
452 int head = 0;
453 int sector = 0;
454 int size = 0;
455
456 int headerpos = 0;
457
458 int interleave = 0;
459 int interleave_prec = -1;
460 bool check_interleave = true;
461 bool check_skew = true;
462
463 int gap1 = 0;
464 int ecctype = 0;
465
466 // if (current_cylinder==0 && current_head==0) showtrack(trackimage, tracksize);
467
468 // If we want to detect gaps, we only do it on cylinder 0, head 0
469 // This makes it safer to detect the header length
470 // (There is indeed some chance that we falsely assume a header length of 4
471 // because the two bytes behind happen to be a valid CRC value)
472 if (save_param(MFMHD_GAP1) && current_cylinder==0 && current_head==0)
473 {
474 m_param.gap1 = 0;
475 m_param.gap2 = 0;
476 m_param.gap3 = 0;
477 m_param.sync = 0;
478 // 4-byte headers are used for the IBM-AT format
479 // 5-byte headers are used in other formats
480 m_param.headerlen = 4;
481 m_param.ecctype = 0;
482 }
483
484 // AT format implies 512 bytes per sector
485 int sector_length = 512;
486
487 // Only check once
488 bool countgap1 = (m_param.gap1==0);
489 bool countgap2 = false;
490 bool countgap3 = false;
491 bool countsync = false;
492
493 chd_error chdstate = CHDERR_NONE;
494
495 if (TRACE_IMAGE)
496 {
497 for (int i=0; i < tracksize; i++)
498 {
499 if ((i % 16)==0) osd_printf_verbose("\n%04x: ", i);
500 osd_printf_verbose("%02x ", (m_param.encoding==MFM_BITS || m_param.encoding==MFM_BYTE)? mfm_decode(trackimage[i]) : (trackimage[i]&0xff));
501 }
502 osd_printf_verbose("\n");
503 }
504
505 // We have to go through the bytes of the track and save a sector as soon as one shows up
506
507 while (bytepos < tracksize)
508 {
509 // Decode the next 16 bits
510 if (m_param.encoding==MFM_BITS || m_param.encoding==MFM_BYTE)
511 {
512 byte = mfm_decode(trackimage[bytepos]);
513 }
514 else byte = (trackimage[bytepos] & 0xff);
515
516 switch (state)
517 {
518 case SEARCH_A1:
519 // Counting gaps and sync
520 if (countgap2)
521 {
522 if (byte == 0x4e) m_param.gap2++;
523 else if (byte == 0) { countsync = true; countgap2 = false; }
524 }
525
526 if (countsync)
527 {
528 if (byte == 0) m_param.sync++;
529 else countsync = false;
530 }
531
532 if (countgap3)
533 {
534 if (byte != 0x00 || m_param.gap3 < 4) m_param.gap3++;
535 else countgap3 = false;
536 }
537
538 if (((m_param.encoding==MFM_BITS || m_param.encoding==MFM_BYTE) && trackimage[bytepos]==0x4489)
539 || (m_param.encoding==SEPARATED && trackimage[bytepos]==0x0aa1)
540 || (m_param.encoding==SEPARATED_SIMPLE && trackimage[bytepos]==0xffa1))
541 {
542 state = FOUND_A1;
543 count = (search_header? m_param.headerlen : (sector_length+1)) + 2;
544 crc = 0x443b; // init value with a1
545 pos = 0;
546 }
547 bytepos++;
548 break;
549
550 case FOUND_A1:
551 crc = ccitt_crc16_one(crc, byte);
552 // osd_printf_verbose("%s: MFM HD: Byte = %02x, CRC=%04x\n", tag(), byte, crc);
553
554 // Put byte into buffer
555 // but not the data mark and the CRC
556 if (search_header || (count > 2 && count < sector_length+3)) buffer[pos++] = byte;
557
558 // Stop counting gap1
559 if (search_header && countgap1)
560 {
561 gap1 = bytepos-1;
562 countgap1 = false;
563 }
564
565 if (--count == 0)
566 {
567 if (crc==0)
568 {
569 if (search_header)
570 {
571 // Found a header
572 ident = buffer[0];
573 cylinder = buffer[1];
574 // For non-PC-AT formats, highest three bits are in the head field
575 if (m_param.headerlen == 5) cylinder |= ((buffer[2]&0x70)<<4);
576 else
577 {
578 osd_printf_verbose("%s: Unexpected header size: %d, cylinder=%d, position=%04x\n", tag(), m_param.headerlen, cylinder, bytepos);
579 showtrack(trackimage, tracksize);
580 }
581
582 head = buffer[2] & 0x0f;
583 sector = buffer[3];
584 int identexp = cylinder_to_ident(cylinder);
585
586 if (identexp != ident)
587 {
588 osd_printf_verbose("%s: Field error; ident = %02x (expected %02x) for sector chs=(%d,%d,%d)\n", tag(), ident, identexp, cylinder, head, sector);
589 }
590
591 if (cylinder != current_cylinder)
592 {
593 osd_printf_verbose("%s: Sector header of sector %d defines cylinder = %02x (should be %02x)\n", tag(), sector, cylinder, current_cylinder);
594 }
595
596 if (head != current_head)
597 {
598 osd_printf_verbose("%s: Sector header of sector %d defines head = %02x (should be %02x)\n", tag(), sector, head, current_head);
599 }
600
601 // Check skew
602 // We compare the beginning of this track with the track on the next head and the track on the next cylinder
603 if (check_skew && cylinder < 2 && head < 2)
604 {
605 m_secnumber[cylinder*2 + head] = sector;
606 check_skew=false;
607 }
608
609 // Count the sectors for the interleave
610 if (check_interleave)
611 {
612 if (interleave_prec == -1) interleave_prec = sector;
613 else
614 {
615 if (sector == interleave_prec+1) check_interleave = false;
616 interleave++;
617 }
618 }
619
620 if (interleave == 0) interleave = sector - buffer[3];
621
622 // When we have 4-byte headers, the sector length is 512 bytes
623 if (m_param.headerlen == 5)
624 {
625 size = buffer[4];
626 sector_length = 128 << (size&0x07);
627 ecctype = (size&0xf0)>>4;
628 }
629
630 search_header = false;
631 if (TRACE_DETAIL) osd_printf_verbose("%s: Found sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector);
632 headerpos = pos;
633 // Start the GAP2 counter (if not already determined)
634 if (m_param.gap2==0) countgap2 = true;
635 }
636 else
637 {
638 // Sector contents
639 // Write the sectors to the CHD
640 int lbaposition = chs_to_lba(cylinder, head, sector);
641 if (lbaposition>=0)
642 {
643 if (TRACE_DETAIL) osd_printf_verbose("%s: Writing sector chs=(%d,%d,%d) to CHD\n", tag(), current_cylinder, current_head, sector);
644 chdstate = chdfile->write_units(chs_to_lba(current_cylinder, current_head, sector), buffer);
645
646 if (chdstate != CHDERR_NONE)
647 {
648 osd_printf_verbose("%s: Write error while writing sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector);
649 }
650 }
651 else
652 {
653 osd_printf_verbose("%s: Invalid CHS data in track image: (%d,%d,%d); not saving to CHD\n", tag(), cylinder, head, sector);
654 }
655 if (m_param.gap3==0) countgap3 = true;
656 search_header = true;
657 }
658 }
659 else
660 {
661 // Let's test for a 5-byte header
662 if (search_header && m_param.headerlen==4 && current_cylinder==0 && current_head==0)
663 {
664 if (TRACE_DETAIL) osd_printf_verbose("%s: CRC error for 4-byte header; trying 5 bytes\n", tag());
665 m_param.headerlen=5;
666 count = 1;
667 bytepos++;
668 break;
669 }
670 else
671 {
672 osd_printf_verbose("%s: CRC error in %s of (%d,%d,%d)\n", tag(), search_header? "header" : "data", cylinder, head, sector);
673 search_header = true;
674 }
675 }
676 // search next A1
677 state = SEARCH_A1;
678
679 if (!search_header && (pos - headerpos) > 30)
680 {
681 osd_printf_verbose("%s: Error; missing DAM; searching next header\n", tag());
682 search_header = true;
683 }
684 }
685 bytepos++;
686 break;
687 }
688 }
689
690 if (check_interleave == false && save_param(MFMHD_IL))
691 {
692 // Successfully determined the interleave
693 m_param.interleave = interleave;
694 if (TRACE_FORMAT)
695 if (current_cylinder==0 && current_head==0) osd_printf_verbose("%s: Determined interleave = %d\n", tag(), m_param.interleave);
696 }
697
698 if (check_skew == false)
699 {
700 if (m_secnumber[0] != -1)
701 {
702 if (m_secnumber[1] != -1)
703 {
704 if (save_param(MFMHD_HSKEW)) m_param.headskew = m_secnumber[1]-m_secnumber[0];
705 if (TRACE_FORMAT) osd_printf_verbose("%s: Determined head skew = %d\n", tag(), m_param.headskew);
706 }
707 if (m_secnumber[2] != -1)
708 {
709 if (save_param(MFMHD_CSKEW)) m_param.cylskew = m_secnumber[2]-m_secnumber[0];
710 if (TRACE_FORMAT) osd_printf_verbose("%s: Determined cylinder skew = %d\n", tag(), m_param.cylskew);
711 }
712 }
713 }
714
715 gap1 -= m_param.sync;
716 ecctype = -1; // lock to CRC until we have a support for ECC
717
718 if (current_cylinder==0 && current_head==0)
719 {
720 // If we want to detect gaps, store the new value into the param object
721 // The other gaps have already been written directly to the param object above,
722 // unless save_param returned false (or we were not on cylinder 0, head 0)
723 if (save_param(MFMHD_GAP1)) m_param.gap1 = gap1;
724 if (save_param(MFMHD_ECC)) m_param.ecctype = ecctype;
725 }
726 return chdstate;
727 }
728
729 /*
730 Deliver default values.
731 */
get_default(mfmhd_param_t type)732 int mfmhd_generic_format::get_default(mfmhd_param_t type)
733 {
734 switch (type)
735 {
736 case MFMHD_IL: return 4;
737 case MFMHD_HSKEW:
738 case MFMHD_CSKEW: return 0;
739 case MFMHD_WPCOM: // Write precompensation cylinder (-1 = none)
740 case MFMHD_RWC: return -1; // Reduced write current cylinder (-1 = none)
741 case MFMHD_GAP1: return 16;
742 case MFMHD_GAP2: return 3;
743 case MFMHD_GAP3: return 18;
744 case MFMHD_SYNC: return 13;
745 case MFMHD_HLEN: return 5;
746 case MFMHD_ECC: return -1; // -1: use CRC instead of ECC
747 }
748 return -1;
749 }
750