Software-based floppy disc data separator

Philip Pemberton classiccmp at
Tue Jun 15 10:37:07 CDT 2010

On 15/06/10 16:10, Chuck Guzis wrote:
> On 15 Jun 2010 at 8:39, Philip Pemberton wrote:
>> No -- the hardware only stores "time since last edge". So the edges
>> are always one "virtual nanosecond" wide. The code extends these to
>> two PLL clock cycles for the DPLL counter reset, and also stores
>> whether there was a data pulse (transition) in the current data
>> window.
> Okay, it was the commentary that was throwing me off.  This looks
> something like the code that I use.

I've done a bit of improvement on the commenting (see below) -- this 
should clarify it a bit. Also, I got GCD mixed up with LCM -- you want 
the greatest common divisor to set TIMER_INCREMENT, not the lowest 
common multiple.

Ideally you want NSECS_PER_* to be as low as possible, and 
TIMER_INCREMENT as close to 1 as possible. Pick a pair of NSECS_PER_... 
values which have a common factor, then divide both by that factor and 
leave TIMER_INCREMENT set to 1.

If you want speed over all else, you can increase TIMER_INCREMENT 
further, which will speed up the loop at a cost of killing accuracy. You 
might be able to turn the clock-error accumulators into floating point 
values, but IME you usually need double-precision for that, and floating 
point math tends to be slower than integer math (even on modern CPUs 
with fast FPUs).

At the end of the day, it's a starting point...

> 	/**
> 	 * This is a software implementation of Jim Thompson's Phase-Jerked Loop
> 	 * design, available from as the PDF file
> 	 * "FloppyDataExtractor.pdf".
> 	 *
> 	 * This consists of:
> 	 *   A data synchroniser which forces RD_DATA to be active for 2 clock cycles.
> 	 *   A counter which increments constantly while the PLL is running, and is
> 	 *     reset to zero when a data bit is detected.
> 	 *   A flip-flop which changes state when the counter reaches half its maximum
> 	 *     value
> 	 *
> 	 * The actual values of NSECS_PER_ACQ and NSECS_PER_PLLCK don't really matter.
> 	 * What actually matters is the ratio between the two -- if you have a 40MHz
> 	 * acquisition clock and a PLL clock of 16MHz (data rate 500kbps), then the
> 	 * starting values will be NSECS_PER_ACQ=25 and NSECS_PER_PLLCK=62.5. Problem
> 	 * is, 62.5 isn't an integer multiple, so we might have issues with
> 	 * short-term clock jitter. So we multiply by two, which gives us
> 	 * NSECS_PER_ACQ=50 and NSECS_PER_PLLCK=125, and a timestep of 0.5ns. Much
> 	 * better.
> 	 *
> 	 * We can also change the PJL Counter maximum value if it makes the math
> 	 * work out better. Be careful though -- reducing the value WILL reduce the
> 	 * number of available phase-shift steps and thus the PLL accuracy.
> 	 *
> 	 * Now we know the ticks-per-acqclk and ticks-per-pllclk values, we can
> 	 * figure out the optimal timer increment --
> 	 *   (gcd == greatest common divisor)
> 	 *
> 	 * Ideally we want a TIMER_INCREMENT greater than 1. If we get an increment
> 	 * of 1, then the loop has to run at 1x speed and will be SLOW. Try
> 	 * increasing NSECS_PER_ACQ and NSECS_PER_PLLCK (multiply them by the same
> 	 * number e.g. 2, 4, 8, ...), then run the gcd again. Problem is, this isn't
> 	 * going to gain much if anything in speed because you're going to be running
> 	 * more loops at a faster rate, thus it's a zero-gain :-/
> 	 */

classiccmp at

More information about the cctalk mailing list