Hi there,
I think I've got the write precompensation stuff figured out (finally!) :)
Back in 1983, Control Data (via their Magnetic Peripherals Inc.
subsidiary) released an application note called "PLO and Write
Precompensation for 5.25-inch FDDs". This has since been scanned and
uploaded to Bitsavers (thanks again, Al!):
<http://www.bitsavers.org/pdf/cdc/discs/floppy/77653447_5inchPrecomp_Aug83.pdf>
The interesting stuff starts on PDF page 31 ("real" page 28). There's a
really good explanation of why peak shift occurs and why precompensation
is needed. This includes diagrams of problematic bit patterns (both the
original data bits and the MFM-encoded transitions) and shows which bit
needs shifting.
These patterns are:
x011
x110
1000
0001
Which encode to MFM as:
Input MFM coded Shifts Correction
----- --------- ------ ----------
x011 --> xx00101x --> Early --> Delay 250ns
1000 --> 01001010 --> Early --> Delay 250ns
x110 --> xx10100x --> Late --> Advance 250ns
0001 --> 10101001 --> Late --> Advance 250ns
*
"Input" is the data before MFM encoding
"MFM coded" is after MFM encoding has been applied
"Shifts" is the direction in which peakshift will shift the transition
The asterisk denotes the transition which must be shifted
If you're working on raw bits, that's fine -- and indeed, this matches
up perfectly with what's in the Western Digital FD179x-01 application
notes (Figure 6: "Internal Write Precomp Algorithm") and Jean
Louis-Guerin's WD1772 documentation.
But what if we choose to feed the data to an MFM encoder (which converts
every bit into two bits) and then process the output of that in a
bit-serial manner? Well, in that case, we only need to match two bit
patterns:
00101 --> Early --> Delay 250ns
10100 --> Late --> Advance 250ns
*
And thus this precompensation code was born:
uint8_t shiftreg = 0;
int n = 0;
for (vector<bool>::iterator bit = bits.begin(); bit != bits.end(); bit++) {
shiftreg = ((shiftreg << 1) | (*bit ? 1 : 0));
// The shift register delays the output by 2 bits
if (n < 2) {
n++;
continue;
}
switch (shiftreg & 0x1F) {
case 0x05: // 00101 (MFM x011 or 1000) - causes early shift
printf("Early Shifted %d\n", shiftreg&4?1:0);
break;
case 0x14: // 10100 (MFM x110 or 0001) - causes late shift
printf("Late Shifted %d\n", shiftreg&4?1:0);
break;
default:
printf("Normal %d\n", shiftreg&4?1:0);
break;
}
}
Typical precompensation for 5.25-inch floppies, by the way, is 250
nanoseconds. I'm not sure what it is for 3.5-inch, or indeed for other
data rates (if data rate has a bearing on peak shift).
Enjoy!
--
Phil.
philpem at philpem.me.uk
http://www.philpem.me.uk/