Codificacion MFM en Verilog

Dudas, cuestiones, sugerencias y peticiones en general sobre el proyecto / Questions and requests about the project
Responder
wilco2009
Mensajes: 96
Registrado: 23 Ene 2016, 20:17

Codificacion MFM en Verilog

Mensaje por wilco2009 » 10 Abr 2017, 17:00

Pues eso, que como parte de un hipotético chip controlador de disquetera me he propuesto comprender como funciona el protocolo MFM, esto es un primer paso, ya que luego habría que meterse con toda la parte de comandos.

El tema es que he estado peleandome con la info que hay por ahí al respecto de la codificación MFM y he llegado a la conclusión de que es más sencillo de codificar, que de decodificar.
Tras muchos dolores de cabeza, parece que que he llegado a realizar un algoritmo que, sobre el simulador, parece que funciona, pero aun me queda alguna dudilla que otra, por lo que la suelto por aquí a ver si alguien conoce la respuesta.

El protocolo MFM viene más o menos bien descrito aquí, aunque como decía no explican como decodificar y utilizarlo para recuperar el reloj, aunque creo que he dado con la clave y el resultado es el fuente de más abajo en Verilog.

El tema es la sincronización inicial. En la Wikipedia dice que hay que utilizar una cadena "100010010001001" como marca de sincronización, que coincide con el byte $A1, pero que le falta un bit de reloj.

Pero, ¿como funciona exactamente esto?.
¿Tenemos el bus normalmente a 0 y cuando empieza la transmisión recibimos esta cadena?. Debemos por tanto estar monitorizando todo el rato el bus de datos manteniendo un buffer de 12 bits e ignorar todo lo que venga hasta el momento que detectemos dicha cadena.

¿Vienen los datos inmediatamente después de la marca de sincronismo?

¿Como sabemos que ha terminado la transmisión de datos?

¿Hay algún sitio donde se explique esto con más detalle?

Después de resolver esto, ya me plantearé como funciona el tema de los comandos de la disquetera.

Quizás (aunque supongo que ni siquiera se plantea) pero es posible que pueda resultar útil en el futuro para implementar un interface de disquetera en el zxUNO.

Código: Seleccionar todo

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:    20:44:58 04/04/2017
// Design Name:
// Module Name:    MFM
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module MFM(
    input clk16,
    input nrst,
    input MFMData,
    output Data_out,
    output Clock_out
    );
   
   reg [3:0] counter = 0;
   reg clk8 = 0;
   reg flipflop = 0;
   reg dato = 1;
   reg reloj = 0;
   reg pending = 0;
   
   assign Clock_out = flipflop;
   assign Data_out = dato;

   always @(posedge clk16 or negedge nrst) begin
      if (!nrst) begin
         counter = 0;
         clk8 = 0;
         flipflop = 1'b0;
         reloj = 1'b0;
         dato = 1'b1;
      end else begin
         clk8 = !clk8;
         if (clk8) begin
            flipflop = 0;
         end
         if (MFMData==1'b1) begin
            if (counter > 5) begin   // 3
            // prev: dato=0   reloj=0
            // act : dato=1   reloj=0
            // periodo = largo
               dato = 1'b1;
               reloj = 1'b0;
               flipflop = 1'b1;
            end else if (counter > 3 ) begin // 2
               if ((reloj == 0) && (dato == 1)) begin
            // prev: dato=1   reloj=0
            // act : dato=1   reloj=0
            // periodo = medio
                  dato = 1'b1;
                  reloj = 1'b0;
                  flipflop = 1'b1;
               end else if ((reloj == 1) && (dato == 0)) begin
            // prev: dato=0   reloj=1
            // act : dato=1   reloj=0
            // periodo = medio
                  dato = 1'b1;
                  reloj = 1'b0;
                  flipflop = 1'b1;
               end else   if ((reloj==0) && (dato == 0)) begin
            // prev: dato=1   reloj=0
            // act : dato=1   reloj=0
            // periodo = medio
            // este es un 0 pero como estamos en el reloj
            // debemos esperar al momento del dato para asignar
                  pending = 1'b1;
               end

            end else if (counter > 1) begin  // 1
            // prev: dato=1   reloj=0   ?????????? por aquí entra en primer lugar
            // act : dato=1   reloj=0
            // periodo = medio
               if ((reloj== 0) && (dato==1)) begin
                  dato = 1'b1;
                  reloj = 1'b0;
                  flipflop = 1'b1;
               end else
            // prev: dato=0   reloj=1   ?????????? por aquí entra en primer lugar
            // act : dato=0   reloj=1
            // periodo = medio
            // este es un 0 pero como estamos en el reloj
            // debemos esperar al momento del dato para asignar
               if ((reloj== 1) && (dato==0)) begin
                  pending = 1'b1;
               end
            end
            counter = 1'b0;
         end else begin
            counter = counter + 1;
            if (counter > 7) begin
            // prev: dato=0   reloj=1
            // act : dato=0   reloj=1
            // periodo = largo
               if (dato==0) begin
                  dato = 1'b0;
                  reloj = 1'b1;
                  flipflop = 1'b1;
                  pending = 1'b0;
               end
            end else if (counter > 3) begin
               if (dato==1) begin
                  dato = 1'b0;
                  reloj = 1'b0;
                  flipflop = 1'b1;
                  pending = 1'b0;
               end
            end else if (counter > 1) begin
               if ((dato==0) && (reloj==0) && pending) begin
            // prev: dato=0   reloj=0
            // act : dato=0   reloj=1
            // periodo = nulo
                  pending = 1'b0;
                  dato = 1'b0;
                  reloj = 1'b1;
                  flipflop = 1'b1;
               end else if ((dato==0) && (reloj==1) && pending) begin
            // prev: dato=0   reloj=1
            // act : dato=0   reloj=1
            // periodo = nulo
                  pending = 1'b0;
                  dato = 1'b0;
                  reloj = 1'b1;
                  flipflop = 1'b1;
               end
            end
         end
      end
   end
   
endmodule

Avatar de Usuario
Quest
Mensajes: 900
Registrado: 27 Sep 2015, 00:20

Re: Codificacion MFM en Verilog

Mensaje por Quest » 10 Abr 2017, 17:35

Si quieres echar un ojo a alguna implementación de controladora FDC, tienes algunos ejemplos, como por ejemplo de la serie 17xx de Western Digital: https://github.com/svofski/vector06cc/b ... y/wd1793.v

También con alguna mejora para soporte de escritura y demás que hicieron para mist (En SystemVerilog) : https://github.com/sorgelig/Vector06_MI ... /wd1793.sv

Hace un tiempo estuve mirándola para ver cómo acoplarla a algún core, pero me puse con otras cosas.
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA

wilco2009
Mensajes: 96
Registrado: 23 Ene 2016, 20:17

Re: Codificacion MFM en Verilog

Mensaje por wilco2009 » 11 Abr 2017, 11:36

Quest escribió:Si quieres echar un ojo a alguna implementación de controladora FDC, tienes algunos ejemplos, como por ejemplo de la serie 17xx de Western Digital: https://github.com/svofski/vector06cc/b ... y/wd1793.v

También con alguna mejora para soporte de escritura y demás que hicieron para mist (En SystemVerilog) : https://github.com/sorgelig/Vector06_MI ... /wd1793.sv

Hace un tiempo estuve mirándola para ver cómo acoplarla a algún core, pero me puse con otras cosas.
Muchas gracias Quest. La verdad es que es muy interesante y me llevado una alegría al ver que existía, pero resulta que, después de repasar el fuente, me he dado cuenta que no implementa la parte de comunicaciones con la disquetera.
En el código se implementa toda la comunicación con el ordenador, comandos, registros, etc, pero la parte de comunicación con la disquetera la hace mediante buferes en RAM, y en el segundo listado se hace referencia expresa a la lectura en tarjeta SD.

Al final, el tema de la codificación MFM no lo toca.

Ya te digo que de todas formas me lo guardo por que es interesantísmo para implementar la otra parte.

wilco2009
Mensajes: 96
Registrado: 23 Ene 2016, 20:17

Re: Codificacion MFM en Verilog

Mensaje por wilco2009 » 12 Abr 2017, 16:35

Pues ya le he echado una ojeada al proyecto back to the plus 3, y resulta que la lógica del SED es mucho más sencilla de lo que esperaba, pero depende de algunas señales que se retroalimentan del FDC765 y que todavía no acabo de entender.
No acabo de ser capaz de ver la correspondencia de la lógica del SED con la codificación MFM, si no tiene parte de la implementación en el 765.

Al final, la PROM es poco más que un contador algo especial, y su contenido se puede resumir en el siguiente código:

Código: Seleccionar todo

		
		//PROM
		if (!IC9Q[5]) begin  // esto parece un contador desplazado
				IC8O[6:4] = IC9Q[4:2]+1;
				IC8O[7] = IC9Q[4];
		end else begin
			IC8O = IC9Q[4:1]+1;
		end
		
	end
El reloj que le envía al 765, al contrario de lo que yo pensaba, no tiene ningún tipo de corrección, siendo simplemente una división del reloj principal de entrada.

Código: Seleccionar todo

	
	always @(negedge clk16) begin
		cnt = cnt + 1;
	end
	assign wrclk = cnt[1]; // 4MHz	
El meollo de la cuestión es la señal Data Window, que aun no acabo de entender como la genera, ya que también depende de la señal VCO que viene del 765 y es algo así como una señal de sincronización.

Código: Seleccionar todo

	
	always @(negedge IC9Q[4] or negedge VCO) begin
//74LS74 IC10A
		if (!IC9Q[4]) begin
			DW = 1'b1; // IC10A.Q
		end else begin
			DW = !DW; // IC10A.Q
		end
	end 
Luego hay algunas señales que se usan en el esquema de la disquetera original y aquí no las usa, como INT.

El código completo que he convertido es este.

Código: Seleccionar todo

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    08:36:39 04/12/2017 
// Design Name: 
// Module Name:    backtothep3 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module backtothep3(
    input clk16,
	 input VCO,
	 input FDRD,
    output wrclk,
	 output reg RDDATA,
	 output reg DW
    );
	 
	 reg [1:0] cnt = 0;
	 reg [6:1] IC9Q = 0;
	 reg [7:4] IC8O = 4'b1111;

	always @(negedge clk16) begin
		cnt = cnt + 1;
	end
	
	always @(posedge cnt[0] /* 8MHz */) begin
// 74LS174 IC9
		IC9Q[1] = IC8O[4];
		IC9Q[2] = IC8O[5];
		IC9Q[3] = IC8O[6];
		IC9Q[4] = IC8O[7];
		
		IC9Q[5] = !RDDATA;
		IC9Q[6] = RDDATA;


		//PROM
		if (!IC9Q[5]) begin  // esto parece un contador desplazado
				IC8O[6:4] = IC9Q[4:2]+1;
				IC8O[7] = IC9Q[4];
		end else begin
			IC8O = IC9Q[4:1]+1;
		end
		
	end
	
	always @(negedge FDRD or negedge IC9Q[5]) begin
//74LS74 IC10B
		if (!IC9Q[5]) begin
			RDDATA = 1'b0; // IC10B.Q
		end else begin
			RDDATA = VCO; // IC10B.Q
		end
	end 

	always @(negedge IC9Q[4] or negedge VCO) begin
//74LS74 IC10A
		if (!IC9Q[4]) begin
			DW = 1'b1; // IC10A.Q
		end else begin
			DW = !DW; // IC10A.Q
		end
	end 

	assign wrclk = cnt[1]; // 4MHz
	
endmodule

serbalgi
Mensajes: 9
Registrado: 29 Jun 2016, 23:55

Re: Codificacion MFM en Verilog

Mensaje por serbalgi » 16 Abr 2017, 23:58

Wilco, si buscas información en detallada deberías bucear por aquí:
http://info-coach.fr/atari/hardware/FD-Hard.php
http://info-coach.fr/atari/software/FD-Soft.php

wilco2009
Mensajes: 96
Registrado: 23 Ene 2016, 20:17

Re: Codificacion MFM en Verilog

Mensaje por wilco2009 » 17 Abr 2017, 00:27

Gracias!!

Responder