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