Llevo tiempo dándole vueltas al tema de clonar la pareja, FDC765 y SED9540, que para el que no lo sepa son los chips que forman el núcleo de una controladora de floppy disk para Spectrum o para Amstrad.
Por raro que parezca aun nadie ha desarrollado una descripción hardware para implementar estos chips con una CPLD, o al menos no la ha compartido.
Cansado de buscar una descripción ya realizada en verilog, me he decidido a intentar hacerla yo, y entonces he comprendido porqué todavía no lo ha hecho nadie.
El chip FDC765 parece sencillo de implementar, ya que únicamente controla los comandos de lectura y escritura de la disquetera, además de los registros de estado y cosas así, pero el el SED9540 es algo más complicado, ya que es el que se encarga de interpretar la ristra de datos que llegan desde la disquetera y separar los datos de la señal de reloj, reajustando el reloj (clock recovery) cuando es necesario, y enviando al 765 las señales de datos y del reloj ya separadas.
La codificación que usan las disqueteras es la conocida como MFM, que permite albergar la señal de reloj junto con la de datos, permitiendo además reajustar dicha señal, ya que las lecturas provenientes de la disquetera no son siempre constantes debido a factores mecánicos, por lo que es necesario un mecanismo de reajuste.
Para el que quiera profundizar algo más en el tema puede leer
este artículo de la Wikipedia, en el que se explica la codificación, que es bastante sencilla, aunque no se explica como podemos decodificar la señal aprovechándola para reajustar el reloj, por lo que esto me ha llevado más de un dolor de cabeza.
Tras mucho pelearme con el tema he conseguido un éxito parcial, ya que consigo decodificar y reajustar la señal en una CPLD, pero todavía no acabo de entender quién se encarga de gestionar el "sync mark" y como se usa.
Doy por supuesto que dicha marca de sincronización la debe gestionar el SED9540, pero para poder tener claro como lo hace creo que voy a tener que tirar de analizador lógico.
Si alguien conoce el tema en profundidad y me quiere echar un cable, bienvenido sea.
Os dejo aquí el listado funcional en Verilog que decodifica la señal MFM y reajusta el reloj utilizando un reloj auxiliar de 16MHz exactamente igual que se hace en el SED9540.
► Mostrar Spoiler
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
"Nada viaja a mayor velocidad que luz con la posible excepción de las malas noticias las cuales obedecen a sus propias leyes."
Douglas Adams. Guía de autoestopista galáctico.