OpenCores
URL https://opencores.org/ocsvn/floppyif/floppyif/trunk

Subversion Repositories floppyif

[/] [floppyif/] [trunk/] [rtl/] [mfm_read.v] - Rev 3

Compare with Previous | Blame | View Log

// MFM reader
 
module mfm_read
  (
  input reset_l,
 
  // 24 MHz clock
 
  input clk,
 
  // Read pulses in
 
  input read_pulse_l,
 
  // Decoded bytes out
 
  output reg [7:0] data_out,	// Data byte
  output reg mark,		// Set if byte is an address mark
  output reg valid,		// Set if valid
  output reg crc_zero		// Set if CRC is 0 (meaning no errors) after this byte
  );
 
// Clock/Data separator
 
parameter PERIOD = (24 * 256);
// No. clocks per period * 256 (one period is 1/2 bit time: 1us for MFM)
 
parameter HALF = (PERIOD / 2);
 
reg [12:0] count;	// Bit window timer
 
reg capture;		// Set if bit was found in this window
 
reg [2:0] leading;	// Synchronizer and leading edge detector
 
reg sep_clock;
reg sep_data;
 
reg [12:0] adjust; // Amount to add to clock
 
always @(posedge clk or negedge reset_l)
  if (!reset_l)
    begin
      leading <= 3'b111;
      capture <= 0;
      count <= 0;
      sep_clock <= 0;
      sep_data <= 0;
    end
  else
    begin
      sep_clock <= 0;
 
      // Feed leading edge detector
      leading <= { read_pulse_l, leading[2:1] };
 
      // Normal counter increment
      adjust = 256;
 
      // We detect an edge
      if (!leading[1] && leading[0])
        begin
          // Note that edge was detected
          capture <= 1;
 
          // Bump counter: it should be at HALF
          if (count > HALF)
            // We're too fast: retard
            adjust = 256 - ((count-HALF)>>1);
          else if (count < HALF)
            // We're too slow: advance
            adjust = 256 + ((count-HALF)>>1);
        end
 
      // Advance clock
      if (count + adjust >= PERIOD)
        begin
          count <= count + adjust - PERIOD;
          capture <= 0;
          sep_clock <= 1;
          sep_data <= capture;
        end
      else
        count <= count + adjust;
 
    end
 
// Address mark detector, byte aligner
 
reg [15:0] shift_reg;	// Shift register
reg [3:0] shift_count;
 
// Data bits
 
wire [7:0] data = { shift_reg[14], shift_reg[12], shift_reg[10], shift_reg[8],
                    shift_reg[6], shift_reg[4], shift_reg[2], shift_reg[0] };
 
// Clock bits
 
wire [7:0] clock = { shift_reg[15], shift_reg[13], shift_reg[11], shift_reg[9],
                     shift_reg[7], shift_reg[5], shift_reg[3], shift_reg[1] };
 
reg [7:0] aligned_byte;
reg aligned_valid;
reg aligned_mark;
 
always @(posedge clk or negedge reset_l)
  if(!reset_l)
    begin
      shift_reg <= 0;
      shift_count <= 0;
      aligned_mark <= 0;
      aligned_byte <= 0;
      aligned_valid <= 0;
    end
  else
    begin
      aligned_valid <= 0;
      if(sep_clock)
        begin
          shift_reg <= { shift_reg[14:0], sep_data };
 
          if(shift_count)
            shift_count <= shift_count - 1;
 
          if(clock==8'h0A && data==8'hA1 || !shift_count)
            begin
              shift_count <= 15;
              aligned_byte <= data;
              aligned_valid <= 1;
              if(clock==8'h0A && data==8'hA1)
                aligned_mark <= 1;
              else
                aligned_mark <= 0;
            end
        end
    end
 
// CRC checker
 
function [15:0] crc;
input [15:0] accu;
input [7:0] byte;
  begin
    crc[0] = accu[4'h8]^accu[4'hC]^byte[4]^byte[0];
    crc[1] = accu[4'h9]^accu[4'hD]^byte[5]^byte[1];
    crc[2] = accu[4'hA]^accu[4'hE]^byte[6]^byte[2];
    crc[3] = accu[4'hB]^accu[4'hF]^byte[7]^byte[3];
    crc[4] = accu[4'hC]^byte[4];
    crc[5] = accu[4'hD]^byte[5]^accu[4'h8]^accu[4'hC]^byte[4]^byte[0];
    crc[6] = accu[4'hE]^byte[6]^accu[4'h9]^accu[4'hD]^byte[5]^byte[1];
    crc[7] = accu[4'hF]^byte[7]^accu[4'hA]^accu[4'hE]^byte[6]^byte[2];
    crc[8] = accu[4'h0]^accu[4'hB]^accu[4'hF]^byte[7]^byte[3];
    crc[9] = accu[4'h1]^accu[4'hC]^byte[4];
    crc[10] = accu[4'h2]^accu[4'hD]^byte[5];
    crc[11] = accu[4'h3]^accu[4'hE]^byte[6];
    crc[12] = accu[4'h4]^accu[4'hF]^byte[7]^accu[4'h8]^accu[4'hC]^byte[4]^byte[0];
    crc[13] = accu[4'h5]^accu[4'h9]^accu[4'hD]^byte[5]^byte[1];
    crc[14] = accu[4'h6]^accu[4'hA]^accu[4'hE]^byte[6]^byte[2];
    crc[15] = accu[4'h7]^accu[4'hB]^accu[4'hF]^byte[7]^byte[3];
  end
endfunction
 
reg [15:0] fcs;
reg [2:0] count;
 
always @(posedge clk or negedge reset_l)
  if(!reset_l)
    begin
      fcs <= 0;
      count <= 0;
      data_out <= 0;
      mark <= 0;
      valid <= 0;
      crc_zero <= 0;
    end
  else
    begin
      if(aligned_valid)
        begin
          data_out <= aligned_data;
          valid <= 1;
          mark <= aligned_mark;
 
          fcs <= compute_fcs(fcs, aligned_byte);
          crc_zero <= (compute_fcs(fcs, aligned_byte)==16'h0000);
 
          // Ignore address marks after the first one
          if(count)
            count <= count - 1;
          else if(aligned_mark)
            begin
              // Start of packet: initial crc
              fcs <= compute_fcs(16'hFFFF, aligned_byte);
              count <= 4;
            end
        end
      else
        valid <= 0;
    end
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.