P
Philip Pemberton
Guest
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:
http://hg.discferret.com/microcode/file/1b4ea3919380/DiscReader.v
http://hg.discferret.com/microcode/file/1b4ea3919380/
Flag_Delay1tcy_OneCycle.v
(other modules are here if you need them: http://hg.discferret.com/
microcode/file/1b4ea3919380 )
I have also rewritten DiscReader.v to use a free-running counter (which
seems like a better solution) -- that version is here:
http://pastebin.com/evMtjXWj
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,
--
Phil.
philpem@philpem.me.uk
http://www.philpem.me.uk/
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:
http://hg.discferret.com/microcode/file/1b4ea3919380/DiscReader.v
http://hg.discferret.com/microcode/file/1b4ea3919380/
Flag_Delay1tcy_OneCycle.v
(other modules are here if you need them: http://hg.discferret.com/
microcode/file/1b4ea3919380 )
I have also rewritten DiscReader.v to use a free-running counter (which
seems like a better solution) -- that version is here:
http://pastebin.com/evMtjXWj
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,
--
Phil.
philpem@philpem.me.uk
http://www.philpem.me.uk/