Hi guys.
I'm currently working on the HDL code for an open-source project which images 'strange and unusual' magnetic media (mainly floppy discs but also MFM and RLL hard disc drives).
To do this, I measure the time between incoming pulses on the RD_DATA line. One pulse indicates a magnetic transition. The time between a given pair of pulses encodes (in a roundabout way) a data bit. This is a gross oversimplification, but serves the purpose for this explanation.
After measuring the time between two pulses, it re-arms and measures between the second pulse and the one following it. Rinse, repeat.
The captured timing values are stored in an on-FPGA FIFO buffer, then passed onto an off-chip Cypress 100MHz 512K*8bit high speed static RAM (this thing needs A LOT of storage). The period counter's reference clock is 100MHz. 10 nanoseconds per count. The most significant bit is reserved for a 'flag' bit (it's used by other parts of the design), leaving a range of 0 to 127 for the counter.
The problem is, a lot of the timing values are about 800 counts long. To work around this, I implemented logic to store a 'special' value in the stream if the counter overflows from 127 to 0. This value is "8'd0" -- 8 bits, all zeroes.
This raises a problem: if any two incoming pulses are measured at exactly
128 clocks apart (or a modulo thereof), the HDL stores a carry (0x00)... immediately followed by the value of the counter, which is 0x00 (because the count of clock pulses is a multiple of 128). This is messing up the datastream, and I only caught it because a friend mentioned it, I added a test case to the testbench, and I got a truckload of assertion failures.The Verilog code is here:
I have also rewritten DiscReader.v to use a free-running counter (which seems like a better solution) -- that version is here:
Feel free to offer comments on either of these... the rewrite is later code, and as far as I can tell fully synchronous to the clock (the older code has some other corner cases -- hence the rewrite).
Effectively the byte-stream format is: CARRY starts at 0. 0x00 or 0x80 -- add 128 to CARRY. Anything else -- the timing value is CARRY + (this_byte AND 0x7F). Clear CARRY to zero afterwards.
The best idea I've come up with thus far is to scrap the overflow logic, cause the acquisition to abort with an error state if the timer overflows, and use a 12-bit or larger counter (which would allow for a maximum count of 40us). This would of course mean I'd have to rewrite the RAM controller logic to handle a 16-bit stream and chunk it into bytes... :(
Can anyone think of a good way to resolve this, ideally without introducing timing jitter (although the acquisition clock is PLL'd off a
20MHz TTL oscillator, so there's probably a bit of that already)? I'm not overly attached to the bitstream format, so feel free to propose changes.Thanks,