12.6 - EL CONTROLADOR DE DISQUETES NEC 765

12.6.1 - LA TECNOLOGÍA DE GRABACIÓN EN DISCO

Simple y Doble densidad: MF y MFM.

     La superficie magnética de un disco está dividida en pistas concéntricas, en cualquiera de las cuales el cabezal de lectura/escritura puede ser posicionado con ayuda de un motor paso a paso. Los únicos datos que se almacenan en el disco son bits, como se verá. El cabezal de la unidad de disco es, en esencia, una bobina en la que se verifican dos leyes fundamentales de la física electrónica: por un lado, una corriente alterna en dicha bobina provoca un campo magnético que varía al mismo ritmo que la corriente (lo que permite magnetizar la superficie del disco para grabar los datos); por otro lado, aplicando un campo magnético variable de manera constante a la bobina se genera una tensión constante en la misma (lo que permite leer los datos previamente registrados sobre esa superficie magnética, dejando el cabezal deslizarse sobre la misma).

     A simple vista, por tanto, se podría intuir que registrar datos en un disco es una tarea sencilla: se podrían representar los bits (a 1 ó 0) según la presencia/ausencia de magnetización en cada punto de la superficie. Sin embargo, la electrónica y mecánicas de precisión necesarias para este tipo de grabación se escapan aún de las posibilidades tecnológicas actuales. La solución adoptada consiste en registrar, junto a los bits de datos, una frecuencia de reloj de referencia que permita localizar los bits sin problemas: entre dos registros magnéticos de referencia en el disco (marcados con '*'), puede existir o no otro registro (que es lo que implica que el dato sea un 1 ó un 0):

     Esto es lo que se denomina grabación en simple densidad (MF). Al final, la superficie magnética se puede considerar como un conjunto de pequeños imanes magnetizados en un sentido u otro: cuando se recorra el disco con el cabezal en modo lectura, la variación magnética inducirá una corriente cuya interpretación permitirá recuperar los datos grabados.

     La electrónica de este sistema trabaja con dos tiempos básicos diferentes: el que transcurre entre dos impulsos del reloj de referencia (bits a 0) y el que separa un impulso del reloj de referencia de los bit a 1. Un impulso de referencia suele durar unos 500 nanosegundos y la distancia entre estos impulsos es de 8 microsegundos. Por ello, para un byte de datos son necesarios 64 microsegundos: como la disquetera da 300 vueltas por minuto, emplea 200 milisegundos en cada vuelta; esto significa que en cada pista podría almacenar teóricamente 200000/64 = 3125 bytes. En un disco convencional de 80 cilindros y dos caras (160 pistas), esto supone 500000 bytes; sin embargo, estos discos suelen almacenar 1.000.000 (doble densidad) y hasta 2.000.000 de bytes (alta densidad) antes de ser formateados (típicamente 720 Kb y 1,44 Mb tras el formateo). ¿Cómo se las apañan para doblar o cuadruplicar los discos actuales esta capacidad?. La respuesta consiste en emplear los formatos de doble y alta densidad, respectivamente.

     La técnica de grabación en doble densidad (MFM) consiste en prescindir de los impulsos de referencia en la medida de lo posible. El método se basa en no emplearlos para registrar bits a 1, o bien bits a 0 aislados: tan solo se usarán para registrar secuencias de varios bits consecutivos a 0 (de lo contrario, una secuencia de bits a 0, sin impulsos de referencia, implicaría una pérdida de sincronización). Aquí existen ahora tres tiempos diferentes: el intervalo elemental es el lapsus de tiempo entre dos bits a 1; un intervalo de doble duración que éste representa la secuencia de bits 1-0-1; por último, un tercer lapso de tiempo correspondiente a 1,5 intervalos de tiempo elementales es empleado para crear los impulsos de referencia (marcados con '*') o abandonar su generación. Aunque en el gráfico no queda quizá muy claro, este método permite grabar el doble de datos en un mismo intervalo de tiempo que el método de simple densidad:

     Las unidades de alta densidad y las (ya difuntas) de extra alta densidad se basan en una mayor depuración de la electrónica de control, que permite reducir los tiempos de los diversos intervalos.

El formateo del disco: Ejemplo con el NEC 765.

     La división del disco en pistas no es suficiente, ya que la cantidad de datos que almacenan es demasiado elevada (unos 9 Kb por cada cilindro y cara en los discos de alta densidad actuales). Por tanto, se comprende la necesidad de subdividir cada pista en unidades lógicas menores (sectores) de un tamaño razonable, que puedan ser accedidas por separado. En esto consiste el proceso de formateo, en el que el disco queda estructurado como se describirá a continuación. Se ha tomado como referencia el proceso de formateo que realiza el FDC (Floppy Disk Controller) 765 de NEC en MFM (en MF varía ligeramente).

     El disco posee una perforación de índice (el pequeño agujerito de la superficie) que es comprobada por un sensor óptico, lo que permite detectar el inicio de la información grabada en cada pista. Nada más comenzar la pista, hay 80 bytes con el valor 4Eh (ver esquema de la página siguiente): es lo que se denomina el GAP 4A (GAP significa algo así como hueco o espacio). La razón de existencia de este pequeño área se debe a la necesidad de sincronizar las distintas unidades de disco, ya que no todos los sensores ópticos actúan de manera totalmente idéntica. Tras el GAP 4Ah se escriben 12 bytes a 0 en un área denominada SYNC. La misión de estos bytes a cero es crear un área de marcas de sincronismo para que el controlador de disco se sincronice con el reloj de referencia. Tras el campo SYNC viene un área especial de tres bytes denominada Index Address Mark o IAM (marca de dirección índice), que existe sólo al principio de la pista. Tras ella aparece un byte 0FCh y, detrás, un GAP 1, en esta ocasión de 50 bytes con el valor 4Eh: su misión es dar tiempo a que el FDC procese la marca de dirección índice, que será decodificada e interpretada por hardware. Después, a continuación vienen ya los sectores de datos del disco, que tienen todos el mismo formato.

     Los sectores comienzan por 12 bytes de SYNC (a 0), a los que sigue la ID Address Mark o ID-AM (marca de dirección de identificación), también de 3 bytes. Detrás, un byte 0FEh. Tras todo esto, aparece el campo de ID: son 4 bytes que contienen la siguiente información: número de cilindro, cara del disco, número de sector y tamaño de sector (en la forma (LOG2 bytes_por_sector)-7). Esto permite identificar a cada sector por separado. Por razones de seguridad, se realiza una comprobación CRC (especie de suma de seguridad) de 16 bits entre la ID-AM y los 4 bytes del campo ID, cuyo resultado se almacena en los dos bytes inmediatamente siguientes, con objeto de detectar futuros fallos en la integridad de la información. Para dar tiempo al FDC a que se prepare para leer los datos que se vienen encima, hay después un nuevo GAP 2 de 22 bytes con el valor 4Eh. Entre otras razones, este área le sirve al FDC, en las operaciones de escritura, para abandonar la lectura y prepararse para la inminente escritura (tarea que siempre lleva algo de tiempo). Detrás vienen otros 12 bytes SYNC. Tras él otros 3 bytes: constituyen la DATA Address Mark o DATA-AM (similar a la ID-AM o a la IAM) y, finalmente, un byte 0FBh. ¡Ahora sí!, tras ello vienen los datos del sector: puede tener una longitud de 128, 256, 512, 1024, 2048 ó 4096 bytes (según haya sido definido) que nada más ser formateado es inicializado con un valor seleccionable por el usuario. Por supuesto, a este área de datos se le aplica también un algoritmo CRC (junto con los bytes de la DATA AM y el byte 0FBh) y los 2 bytes que se obtienen se graban a continuación. Finalmente, aparece el GAP 3, formado por cierto número de bytes 4Eh seleccionable por el usuario al formatear (típicamente entre 54 y 116). Este último GAP tiene una función muy importante: al escribir un sector en el disco, es difícil que la velocidad de la unidad sea totalmente idéntica a la de la unidad que formateó el disco: si es menor, no sucede nada (el sector ocuparía un pelo menos de disco) pero si es mayor, el GAP 3 evita que se invada el siguiente sector. Cuando se escriben datos, el GAP 3 es mucho menor que cuando se formatea (del orden de la mitad de tamaño), para asegurar que no se invadirá la zona del siguiente sector si la unidad es algo más rápida de lo previsto. Los sectores se suceden unos tras otros hasta completar la pista. Después, el resto del espacio hasta que aparezca de nuevo la perforación de índice se rellena con el GAP 4B final. Todo esto, en MFM (en MF, por ejemplo, los bytes añadidos entre sectores por el 765 -excluyendo el GAP 3- no son 62 en total sino 31).

12.6.2 - DESCRIPCIÓN DEL FDC (Floppy Disk Controller) 765.

     Este controlador de disquetes es un chip muy evolucionado que realiza tareas de un nivel relativamente alto. Fabricado inicialmente por NEC, también lo comercializan Rockwell (R 6765) e Intel (i8272). Sus principales características son: tamaño de sector programable (128, 256, 512, 1024, 2048 ó 4096 bytes), posibilidad de programar todos los datos de las unidades, capacidad para controlar 4 disqueteras, transferencia con o sin DMA, generación de interrupciones; es compatible con múltiples microprocesadores (Z80, 8086,...) y trabaja con un reloj sencillo de una sola fase (4 u 8 Mhz). Soporta densidades MF (simple densidad) y MFM (doble densidad) en unidades estándar de 3, 3½, 5¼ y 8 pulgadas.
SEÑALES DEL 765

Interface con la CPU.
RESET:Reset. Línea de reinicialización al estado por defecto.
-CS:Chip Selection. Línea de selección del integrado.
-RD:Read. Patilla por la que la CPU lee datos del FDC.
-WR:Write. Patilla por la que la CPU escribe datos en el FDC.
A0:Address. Esta línea de dirección define dos direcciones de E/S para comunicar con la CPU. Suele ir conectada al A0 de la CPU.
DB0..7:Data Bus. 8 líneas de datos bidireccionales.
INT:Interrupt. Salida de petición de interrupción a la CPU del FDC, por cada byte transferido.

Señales para el modo DMA.
DRQ:DMA Request. Solicitud de DMA al controlador de DMA.
-DACK:DMA Acknowledge. Señal de reconocimiento de solicitud concedida.
TC:Terminal Count. Línea que indica el final de la cuenta de transferencia en modo DMA; cuando no se emplea el DMA sirve también para acabar la transferencia en sistemas controlados por interrupciones.

Señales para el interface con la disquetera.
DS0-1:Drive Select 0-1. También conocidas como US0-1 (Unit Select). Selecciona una de las cuatro disqueteras conectadas.
HDSEL:Head Select. Selecciona el cabezal en unidades de doble cara.
HDL:Head Load. Empleado para provocar el contacto físico del cabezal sobre el disquete o levantarlo.IDX:Index. Entrada del sensor óptico que detecta el inicio de la pista gracias a la perforación de índice del disquete.
RDY:Ready. Señal enviada por la disquetera indicando que el disco gira a velocidad adecuada (el FDC espera a que se cumpla RDY).
WE:Write Enable. Salida que habilita la escritura de datos en el disquete.
-RW/SEEK:Read Write/Seek. Algunas de las líneas que comunican el FDC con la disquetera tienen doble función (para ahorrar patillas en el chip): esta señal permite elegir la función de las 4 siguientes patillas.
FR/STP:Fit Reset/Step. La función FR permite borrar el error de flip-flop de algunas unidades. La función STP, mucho más utilizada, mueve un paso (un cilindro) la cabeza de lectura/escritura (en la dirección que indica LCT/DIR).
FLT/TRK0:Fault/Track0. La señal FLT es generada por algunas disqueteras en caso de error, pudiendo borrarse a través de la patilla anterior (FR/STP). La salida TRK0 indica cuándo el cabezal alcanza el cilindro 0, gracias a un sensor óptico o mecánico, tras el comando de programación Seek o el de recalibración.
LCT/DIR:Low Current/Direction. La señal LCT es necesaria para limitar la corriente de escritura al acceder a los cilindros más internos, por razones físicas. DIR indica en modo Seek el sentido del movimiento del cabezal.
WP/TS:Write protect/Two Side. La señal WP indica si el disco está protegido contra escritura y es comprobada en las operaciones de lectura/escritura; la señal TS se comprueba en las operaciones Seek y sólo es necesaria en unidades de dos cabezales.
WR DATA:Write Data. Línea de entrada en serie de los datos de escritura (para escribir sector, para formatear,...).
PS0-1:Pre Shift 0-1 (Precompensation). En el formato MFM, el FDC indica a la circuitería electrónica adecuada cómo debe ser escrito el flujo de datos: para la precompensación caben tres estados posibles (Early, Normal y late).
RD DATA:Read Data. Entrada al FDC de datos en serie (bits) procedentes de la disquetera y leídos del disquete.
DW:Data Window. Señal obtenida en un separador de datos a partir de los datos leídos.
VCO:VCO Syn. Esta señal es precisa en el separador de datos PLL para el control del VCO.
MFM:MFM Mode. Indica al FDC si se trabaja en simple o doble densidad.

Alimentación y señales de reloj.
Vcc:Entrada de +5v, el chip no suele consumir más de 150 mA.
GND:Masa.
CLK:Entrada de reloj: 4 u 8 MHz habitualmente.
WR CLK:Entrada de reloj para controlar la transferencia: determina la velocidad de transferencia de datos con la disquetera.

PROGRAMACIÓN DEL '765

     La única línea de direcciones del integrado (A0) define dos únicos puertos de E/S: el primero es el registro principal de estado que sólo puede ser leído. A través del segundo puerto, de lectura/escritura, se accede al registro de datos, a través del cual se programa el FDC, se envían y reciben los datos y se obtienen los resultados.

     Con el FDC se trabaja en tres fases diferenciadas: la fase de comando u orden es empleada para enviar al FDC información sobre lo que tiene que hacer, lo que puede implicar enviar hasta 9 bytes en algunos comandos. A continuación viene la fase de ejecución. Finalmente, la fase de resultados puede obligar a leer del FDC hasta siete informaciones de estado diferentes (hasta que no se leen, el FDC no admite más órdenes). Este es el esquema general, si bien algunas órdenes carecen de fase de resultados, otras no tienen fase de ejecución...

     El FDC dispone de 5 registros de estado internos. El principal puede ser accedido directamente como se vio (A0=0) en cualquier momento. Los otros 4 registros (ST0, ST1, ST2 y ST3) sólo son accesibles en algunas órdenes y durante la fase de resultados.

1) COMANDO LEER DATOS.

     Para que el FDC lea los datos del disco hay que enviarle 9 bytes de información en la fase de órdenes. Este activa la señal Head Load y espera el tiempo de Head Load programado. El FDC comienza a leer los ID's (identificadores) de los sectores hasta encontrar el sector buscado, con lo que pasa a la fase de ejecución, o hasta encontrar por segunda vez la perforación de índice del disco (en ese caso se pasa a la fase de resultados para dar el error). En la fase de ejecución, los datos son leídos del disco y enviados al procesador o al DMA, a razón de un byte cada 8, 16, 26.67 ó 32 microsegundos (según la densidad empleada: a 1000, 500, 300 y 250 Kbit/seg respectivamente). Tras acabar la transferencia del último byte del último sector hay que dar un impulso en la patilla TC (Terminal Count) del 765 para evitar que siga leyendo los sectores que van detrás en el proceso denominado multi-sector-read (se leen más sectores hasta llegar al final de la pista). En este comando, al igual que en alguno más, se puede igualar el último sector de la pista al primero a ser accedido, pudiéndose prescindir en ese caso de la señal TC al acceder a un solo sector. De todas maneras, al emplear el DMA, la transferencia finalizará realmente cuando el registro contador del DMA alcanza el valor 0, al encargarse el propio controlador de DMA de activar la señal TC, pudiéndose leer por tanto el número de sectores deseado. Personalmente he comprobado que el último número de sector en la pista es más bien el último sector al que se desea acceder. Este comando produce 7 bytes en la fase de resultados, que deben ser leídos obligatoriamente para que el FDC pueda admitir más órdenes.

2) COMANDO ESCRIBIR DATOS.

     Este comando es totalmente análogo al de lectura, pero actuando en escritura sobre el disco. La secuencia de bytes a enviar y recibir es idéntica: sólo cambian algunos bits del primer byte de comando.

3) COMANDO LEER DATOS BORRADOS.

     Por sector borrado se entiende aquel cuyo DATA-AM está borrado (por haber sido grabado dicho sector con el comando Escribir Datos Borrados): estos sectores son ignorados en las operaciones normales de lectura y escritura, aunque esta orden también permite leerlos. Por supuesto, esto no tiene relación alguna con la recuperación de ficheros borrados en la unidad y la utilidad de este comando es bastante cuestionable.

4) COMANDO ESCRIBIR DATOS BORRADOS.

     Este comando graba sectores con el DATA-AM borrado, con objeto de que sólo puedan ser leídos con el comando Leer Datos Borrados. La secuencia de bytes a enviar/recibir es idéntica al comando Leer Datos: sólo cambian algunos bits del primer byte.

5) COMANDO LEER PISTA.

     Este comando es similar a Leer Datos, se diferencia en que se leen todos los sectores de la pista (si el último número de sector se indica correctamente) empezando cuando se detecta el paso de la perforación de índice (si el sector inicial indicado no es realmente el primer sector de la pista, se producirá error). Aún en caso de error de CRC en el campo de ID o en el de datos, se continúa leyendo la pista.

6) COMANDO FORMATEAR PISTA.

     Este comando de 6 bytes realiza de manera automática y sin dar trabajo al programador todas las tareas necesarias para inicializar una pista del disquete. Tras enviar el comando, habrá que pasar al FDC 4 bytes por cada sector que haya en la pista a formatear: en ellos, para cada sector se indica el número de sector deseado, lo que permite numerar los sectores de manera no consecutiva. El factor de Interleave 1:N de un disco equivale al número N de vueltas que hay que dar para acceder una vez a toda la pista (depende de que los sectores estén numerados consecutivamente o no); elegir un interleave óptimo es decisivo para mejorar el rendimiento (si la unidad gira lo bastante rápida como para que no de tiempo a acceder a dos sectores físicamente consecutivos, el interleave debería ser mayor de 1:1; de lo contrario sería necesaria una vuelta completa del disco cada vez que se accede a dos sectores de número consecutivo, que resulta ser además lo más frecuente). El formateo comienza cuando el sensor correspondiente detecta el inicio de la pista (por la perforación de índice), por ello todas las pistas quedan con los sectores colocados exactamente en la misma posición física: así, el sector N en una cara del disco coincide en su posición con el de la otra y con el del cilindro adyacente (si se numeran todas las pistas igual, claro).

7) COMANDO LEER ID.

     Este comando permite leer del disquete el siguiente ID que aparezca. El ID asociado a cada sector son los 4 bytes asignados durante el formateo, y consiste en información relativa al número de cilindro, número de cabeza, número de sector y tamaño del mismo. Estos números suelen coincidir con los valores físicos reales relacionados con la posición que ocupa el sector en el disco, si bien se pueden falsear en técnicas de protección de datos, aunque los copiones más ordinarios esquivan sin problemas estas trampas tan simples. Este comando consta de sólo 2 bytes; en la fase de resultado devuelve la misma información que el comando Leer Datos (precisamente, la información solicitada).

8), 9) y 10) COMANDOS PARA VERIFICAR (SCAN).

     El comando verificar (SCAN) permite al FDC comparar los datos almacenados en el disquete con un byte enviado por el procesador. Hay 3 comandos Scan de verificación, que indican el modo de comparación por cada byte cotejado: igual, menor o igual, mayor o igual. El comando finaliza cuando se cumple el criterio de comparación elegido en todo el sector dado, cuando se comprueba el último sector de la pista o bien cuando se activa la patilla TC. La secuencia de bytes a enviar (9 en total) y a recibir es casi idéntica al comando Leer Datos:

11) COMANDO DE RECALIBRADO.

     Este comando mueve el cabezal al cilindro 0 del disco. El FDC comienza a generar impulsos (por medio de la línea ST) para mover el motor paso a paso hasta que se le informe que ya se ha alcanzado el cilindro 0 (a través de la patilla TRK0 del 765); en cualquier caso, el comando finaliza tras enviar un máximo de 77 impulsos a la unidad (de ahí que pueda ser preciso repetirlo en las actuales unidades de 80 cilindros, que siguen comportándose así por compatibilidad). Este comando carece de fase de resultados (puede evaluarse el resultado por medio del registro de estado) y consta de sólo 2 bytes.

12) COMANDO DE POSICIONAMIENTO DEL CABEZAL (SEEK).

     El 765 posee 4 registros internos que memorizan la posición del cabezal (sobre qué cilindro se halla) en las 4 unidades de disco soportadas; tras el comando de recalibrado son puestos a 0. Cuando se envía este comando al FDC, para colocar el cabezal sobre un cierto cilindro, éste comprueba si ya se encuentra sobre el mismo: en caso contrario, genera las señales de control necesarias para instruir a la disquetera. Este comando no posee fase de resultados: para comprobar el éxito de la operación hay que emplear la orden Leer Estado de Interrupciones obligatoriamente (de lo contrario, el FDC no aceptará más órdenes de lectura o escritura). En cualquier caso, si la siguiente operación es de escritura, tras este comando hay que hacer una breve pausa (15 ms vale) porque si el cabezal no ha dejado de vibrar acarrearía una escritura incorrecta (se detectaría gracias al CRC en una lectura posterior, pero ¡casi nadie verifica tras escribir!: mejor asegurar que no hay error). Si la siguiente operación es de lectura, no es necesaria dicha pausa ya que en caso de fallar, sería reintentada y no tendría mayor consecuencia. Si se trata de seleccionar el otro cabezal en el mismo cilindro, después de haber posicionado el otro, tampoco es necesaria pausa alguna. Abusar de las pausas podría acarrear una ralentización del acceso, al no hallarse en ocasiones el sector buscado hasta la siguiente vuelta del disco. 3 bytes:

13) COMANDO LEER ESTADO DE INTERRUPCIONES (REGISTRO DE ESTADO 0).

     El 765 genera interrupciones al final de un comando Seek/Recalibrado o debido a un cambio en la señal RDY (Ready) de alguna unidad; en modo NO-DMA las genera además al inicio de la fase de resultados y durante la fase de ejecución. Las dos últimas causas pueden ser reconocidas con facilidad por el microprocesador, pero con las primeras es preciso emplear este comando para conocer la causa con exactitud, gracias a los bits del registro ST0. Esta orden se compone de un solo byte, devolviendo otros 2 en la fase de resultado:

14) COMANDO LEER ESTADO DE UNIDAD (REGISTRO DE ESTADO 3).

     Esta orden permite obtener el contenido del registro de estado ST3 de la unidad deseada, siendo éste el único medio de conseguirlo. Consta de sólo dos bytes, obteniéndose un solo byte de resultado:

15) COMANDO SPECIFY (ESTABLECER DATOS DE LA UNIDAD).

     Aunque descrito en último lugar, este comando debería ser el primero ejecutado antes de comenzar las operaciones de disco. Sirve para indicar si se va a trabajar con DMA o no, así como los tres tiempos básicos que regirán la operación del chip. Estos tiempos están en función de la velocidad de reloj empleada, dependiente de la densidad de disco seleccionada. El comando emplea 3 bytes y carece de fase de resultados.

Step Rate Time: Tiempo comprendido entre dos impulsos consecutivos en la señal que mueve el motor paso a paso del cabezal (lo que determina el tiempo de acceso cilindro-cilindro). Depende de las características físicas de la unidad. El valor para los bits SR se calcula con la fórmula (16-SR)*2 en unidades DD y con (16-SR) en unidades HD (tiempos expresados en milisegundos).
Head Load Time: Tiempo de demora tras activar la señal Head Load, sólo relevante por lo general en unidades de 8" (en las demás suele cargarse el cabezal nada más activarse la señal Motor On). El tiempo 'Head Load' (bits HL) se calcula con la fórmula (HL+1)*4 en unidades DD y (HL+1)*2 en las unidades HD. La unidad de medida es el milisegundo.
Head Unload Time: Tiempo esperado, tras el último acceso al disco, hasta que la señal Head Load vuelva a ser inactiva (sólo suele ser realmente significativo, una vez más, en las unidades de 8"). Las viejas unidades de 8" normalmente estaban girando continuamente (para evitar sus lentas aceleraciones y frenados por la inercia) y levantar o bajar el cabezal era un medio de protección de la superficie magnética. El tiempo 'Head Unload' (bits HU) se calcula con la fórmula HU*32 en unidades DD y con HU*16 en unidades HD. La unidad de medida es el milisegundo.


LOS REGISTROS DE ESTADO DEL 765.

     Como se comentó, el 765 dispone de 5 registros de estado: el registro principal de estado, que puede ser accedido en cualquier momento; los registros ST0, ST1 y ST2 que se obtienen como resultado de diversas órdenes; y el registro ST3. Los registros ST1 y ST2 no se pueden leer directamente (sólo se obtienen como resultado de algunas órdenes), pero ST0 y ST3 pueden ser leídos con un comando al efecto.

El Registro Principal de Estado.

     En este registro se representan en todo momento los datos más importantes sobre el estado del FDC. Sirve también para regular la comunicación entre el microprocesador y el FDC. Significado de sus bits:
Bit 7 (RQM):Request For Master (listo para E/S). Cuando este bit está a 1, el FDC está listo para recibir o enviar bytes a través del registro de datos; en caso contrario no es posible la transferencia.
Bit 6 (DIO):Data Input/Output (entrada/salida de datos). Cuando este bit está a 1, significa que el FDC tiene un byte preparado para el procesador. Cuando está a 0, quiere decir que está esperando un byte del procesador. Este bit no es válido hasta que RQM=1.
Bit 5 (NDM):Non DMA Mode (Modo no-DMA). En modo no DMA estará a 1 si empezó la fase de ejecución; pasa a valer 0 cuando dicha fase finaliza.
bit 4 (CB):FDC Busy (FDC ocupado). Cuando está a 1, el FDC está elaborando una orden de lectura o escritura y, por tanto, no puede procesar más comandos. Este bit se pone a 1 nada más recibir el primer byte de un comando, y baja cuando es leído el último byte de resultados.
Bits 0..3 (DB):FDD0..3 Busy (unidad ocupada). Cada bit está asociado a una unidad (de la A:-D:). Cuando se inicia un comando Seek o un recalibrado en alguna unidad, su bit se activa: mientras alguno de estos bits esté a 1, no se podrán enviar órdenes de lectura o escritura al FDC, pero sí más comandos Seek o de recalibrado de las demás unidades. Estos bits no se ponen a 0 por sí solos: se borran enviando el comando Leer Estado de Interrupciones (si había finalizado ya el comando Seek o el recalibramiento).

El Registro de Estado 0 (ST0).

     Este registro se denomina también registro de estado de interrupciones, ya que en modo no DMA permite identificar la causa de las interrupciones.
Bits 7, 6:Interrupt Code (código de interrupción). Con la notación Bit7-Bit6 se tiene: 00 -Normal Termination ó NT: comando finalizado con éxito. 01 -Abnormal Termination óAT: terminación brusca (comando iniciado pero no terminado): puede deberse a un error real o puede que no, ya que algunos sistemas no emplean la señal TC y es necesario programar en ellos el último sector de la pista como el último sector a acceder. 10 -Invalid Command Issue (IC): comando inválido (comando que no puede empezar al ser ilegal; puede producirse también si se ejecuta el comando Leer estado de Interrupciones sin haber ninguna en ese momento). 11 -Terminación anormal (esta señal se produce ante una variación de la línea RDY (Ready) durante el comando, que empieza pero no finaliza -por ejemplo, si se retira el disquete de la unidad en medio de una operación-).
Bit 5 (SE):Seek End (Fin de Seek). Este bit se pone a 1 cuando acaba la operación Seek.
Bit 4 (EC):Equipment Check (comprobación de equipo). Este bit se pone a 1 si la unidad informa de un error; también puede ponerse a 1 si, tras un recalibrado, no aparece aún la señal TRK0 que indica que se ha alcanzado el cilindro 0. Esto puede suceder si el cabezal está sobre un cilindro superior al 77, ya que el obsoleto FDC (y las más modernas controladoras de disco, por compatibilidad) sólo lo mueven un máximo de 77 cilindros antes de considerar que el intento ha fallado (repítase el recalibrado).
Bit 3 (NR):Not Ready (no preparado). Se activa cuando la unidad informa de esta condición; también cuando se intenta acceder al segundo cabezal en unidades que solo tienen uno.
Bit 2 (HD):Head Address (dirección de cabezal). Indica el cabezal activo en el momento de la interrupción.
Bits 1, 0 (US):Unit Select (Unidad activa): unidad activa durante la interrupción (0-A y 1-B; en PS/2 01-A y 10-B).

El Registro de Estado 1 (ST1).

     Este registro informa, durante la fase de resultados, sobre el desarrollo de la fase de ejecución de los diversos comandos.
Bit 7 (EN):End of Cylinder. Este bit se pone a 1 si se intenta acceder a un sector tras alcanzar el fin de pista programado.
Bit 6:No utilizado (a 0).
Bit 5 (DE):Data Error (error de datos). Se pone a 1 si al leer los datos y calcular su CRC (o al calcular el CRC de los campos de ID), éste no coincide con el CRC almacenado en el disco junto a dichos datos óIDs cuando fueron grabados.
Bit 4 (OR):Overrun (excedido el tiempo de transferencia). Los datos transitan entre el microprocesador y el FDC a una velocidad mínima determinada (8, 16, 26.67 ó32 microsegundos). Si al leer datos del FDC el procesador no es suficientemente rápido, puede llegar un dato sobrescribiendo el anterior cuando aún no había sido leído, lo que provoca que este bit se ponga a 1 para señalar el error.
Bit 3:No utilizado (a 0).
Bit 2 (ND):No Data (no hay datos). Se pone a 1 durante la lectura o scan si el FDC no puede hallar el sector indicado. Se pone también a 1 con el comando leer ID si el FDC no puede leer sin errores el campo ID (si falla el CRC). Por último, también se pone a 1 si en el comando leer pista el sector inicial no es encontrado.
Bit 1 (NW):Not Writable (escritura no permitida). Se pone a 1 al ejecutar algún comando que implique modificar el contenido del disco, si este está protegido contra escritura.
Bit 0 (MA):Missing Address Mark (Address Mark perdida). Se pone a 1 cuando en la lectura el FDC no halla, al cabo de una vuelta completa del disco, la ID de sector. La ausencia de Data Address Mark (y la ausencia también de una Data Address Mark borrada) pone a 1 este bit (junto al bit MD del registro de estado 2).

El Registro de Estado 2 (ST2).
Bit 7:No utilizado (a 0).
Bit 6 (CM):Control mark (marca de control). Se pone a 1 si el FDC halla una Data Address Mark borrada durante una lectura o comando de scan.
Bit 5 (DD):Data Error in Data Field (error en campo de datos). Se pone a 1 si hay error de CRC, pero sólo en el CRC correspondiente al campo de datos.
Bit 4 (WC):Wrong Cylinder (cilindro erróneo). Al formatear la pista, se graba para cada sector información relativa al número de cilindro, número de cabeza, número de sector y tamaño del mismo. Si al leer después dicha pista hay contradicción entre el nº de cilindro solicitado y el nº de cilindro que fue registrado al formatear (debido normalmente a un posicionamiento del cabezal en un cilindro erróneo), este bit se pone a 1.
Bit 3 (SH):Scan Equal Hit (resultado de scan igual). Tras un comando de scan con la condición de igual, este bit se pone a 1 para indicar que la comparación resultó correcta en todos los bytes.
Bit 2 (SN):Scan Not Satisfied (scan no satisfecho). Si tras un comando de scan cualquiera no se halla ningún sector en la pista que corresponda con las especificaciones, este bit se pone a 1.
Bit 1 (BC):Bad Cylinder (cilindro defectuoso). Este bit es similar al WC, con la diferencia de que se pone a 1 si el número de cilindro leído es 0FFh y no coincide con el de la orden.
Bit 0 (MD):Missing Address Mark in Data Field (falta marca de direcciones en campo de datos). Se pone a 1 si en la lectura de datos no aparece una Data Address Mark (ni siquiera borrada).

El Registro de Estado 3 (ST3).

     Este registro de estado sólo puede ser consultado por medio de la orden Leer estado de unidad. Se obtiene la siguiente información:
Bit 7 (FT):Fault (fallo). Este bit se corresponde con la línea Fault de algunas unidades.
Bit 6 (WP):Write protected (protección contra escritura). Si este bit está a 1, significa que el disco introducido en la unidad está protegido contra escritura.
Bit 5 (RDY):Ready (preparado). Este bit se corresponde con la línea RDY (Ready) de la unidad. Si está a 1, la unidad está preparada.
Bit 4 (T0):Track 0 (cilindro 0). Este bit se corresponde con la línea TRK0 de la unidad. Si está a 1, el cabezal de la unidad y cara elegidas se encuentra en ese momento en el cilindro 0.
Bit 3 (TS):Two Side (dos caras). Si este bit está a 1, la unidad de disco posee dos cabezales.
Bit 2 (HD):Head Address (dirección del cabezal). Este bit se corresponde con la línea Head Select del FDC.
Bits 1, 0 (US):Unit Select (unidad seleccionada). Estos bits se corresponden con el estado de dichas líneas del FDC.

12.6.3 - EL 765 DENTRO DEL ORDENADOR.

     El controlador de disquetes es accedido a través de dos puertos de E/S, en la dirección 3F4h (registro de estado) y en la 3F5h (datos). Adicionalmente, existe un registro denominado Registro de Salida Digital, en la dirección E/S 3F2h, que controla los motores de las unidades y permite reinicializar el sistema de disco y seleccionar la modalidad de operación (con o sin DMA). Los valores de bits establecidos para el registro de salida digital son los siguientes (los PS/2 sólo soportan dos disqueteras y el bit 1 está reservado):

     Tras poner a 0 el bit que reinicializa el FDC hay que devolverlo a 1 y (con o sin las interrupciones habilitadas en el bit 3) esperar la interrupción de disquete que vendrá (IRQ6 -> INT 0Eh) ejecutando después el comando leer estado de interrupciones; también hay que recalibrar, ya que el registro interno del FDC que indica el cilindro actual es puesto a 0. En las máquinas 486 en particular, es necesario hacer una leve pausa tras bajar este bit, ya que devolviéndolo inmediatamente a 1 sucede que en ocasiones el 765 no se entera del cambio ¡y no se resetea! (algunos microsegundos bastan). Efectuar un reset es conveniente tras un error de disco. En las máquinas AT o con controladoras de alta densidad existe otro registro más al que se accede en lectura, el Registro de Entrada Digital (3F7h). Su bit más significativo indica si ha habido cambio de disco en la última unidad seleccionada a través del registro de salida digital; los restantes bits se emplean para gestionar el disco duro. Una vez detectada la condición de cambio de disco, hay que bajar este bit para detectar futuros nuevos cambios por el procedimiento, un tanto extraño y quizá absurdo de llevar el cabezal al cilindro 1 y después al 0. Para leer la línea de cambio de disco el motor debe estar encendido (se puede encender, leer la línea y volver a apagarlo después tan deprisa que el usuario no note siquiera parpadear el led de la disquetera). Si no se puede bajar este bit será debido a que no hay disquete introducido. También a través del puerto 3F7h, pero actuando como salida, se accede al Registro de Control del Disquete, que permite seleccionar la velocidad de transferencia de la unidad en sus dos bits menos significativos:

          00 -   500.000 bits/segundo  (disquetes de alta densidad de 1.2M y 1.44M)
          01 -   300.000 bits/segundo  (disquetes de 360K en unidades de 1.2M)
          10 -   250.000 bits/segundo  (disquetes de 3½ - 720K).
          11 - 1.000.000 bits/segundo  (disquetes de 3½ - 2.88M).

     Seleccionar la velocidad correcta en los AT es un requisito totalmente indispensable para lograr enviar y recibir datos del disco. Las unidades de alta densidad de 1.2M siempre trabajan con 80 cilindros, lo que sucede es que pueden leer discos de doble densidad saltando los cilindros de dos en dos. Esto significa que para leer el cilindro 15 de un disco de 360K, será necesario mover el cabezal al cilindro 30 (y programar el 765 para leer el 15, por supuesto, ya que ha sido formateado con ese número). La BIOS automatiza este tipo de operaciones, pero cuando se accede directamente al disco no queda más remedio que considerarlas. En los discos de 3½ nunca es necesario esto, ya que tienen siempre 80 cilindros. En la terminología anglosajona, la velocidad de transferencia se denomina data transfer rate y el movimiento doble del cabezal en los discos de doble densidad recibe el nombre de double stepping. Los PS/2 poseen en 3F0h y en 3F1h dos registros de estado adicionales que no es preciso considerar.

     Un consejo útil para los programadores en ensamblador es que realicen siempre una pequeña pausa de algunos microsegundos (40-60) entre bytes sucesivos de un comando enviado al 765. La razón para ello no está muy clara, pero las BIOS AMI de 486 hacen esto y sus motivos tendrán. Accediendo desde un lenguaje de alto nivel o en procesadores 386 o inferiores esto probablemente no es necesario.

12.6.4 - DENSIDADES DE DISCO Y FORMATOS ESTÁNDAR.

     Las unidades de 5¼ de doble densidad giran a 300 r.p.m. (revoluciones por minuto); esto significa que dan una vuelta cada 200 milisegundos. La velocidad de transferencia empleada es de 250 Kbit/segundo. Echando cuentas, en 200 ms se pueden registrar unos 250000*0,2 = 50000 bits de datos = 6250 bytes por pista. Los disquetes de 360K poseen 9 sectores de 512 bytes; por cada sector hacen falta además 62 bytes que añade el NEC765 (ver al final del apartado 12.6.1) y otros 80 de GAP 3 que estima oportuno IBM: en total, 654 bytes. Así, en la pista no caben 10 sectores pero sí los 9 citados. Como hay 40 cilindros en estos disquetes (y dos caras) en total caben 9*40*2 = 720 sectores (que equivalen a 360 Kb). Por supuesto, estrechando algo el GAP 3 al formatear sí se pueden introducir 10 sectores, maniobra bastante fiable que realizan ciertos formateadores avanzados. Sin embargo, IBM fue excesivamente conservadora al principio, ya que sólo formateaba 8 sectores por pista; luego se dio cuenta y rectificó. Eran los viejos discos de 320 Kb, totalmente obsoletos aunque soportados aún por el FORMAT del DOS. También han existido antaño formatos de 180 e incluso 160 Kb, basados en unidades de una sola cabeza. Las unidades de 5¼ de alta densidad giran a 360 r.p.m.; esto supone 166,66 ms por cada vuelta del disco. El aumento de velocidad se decidió por motivos de fiabilidad. A nadie se le escapa que si el disco girara más lento y se le enviaran los datos a la misma velocidad, cabrían más datos... pero todo tiene un límite (lo contrario sería un chollo). La pretensión de IBM de elevar excesivamente -para la tecnología del momento- la velocidad de transferencia (de 250 a 500 Kbit/seg) obligó a tomar la medida de acelerar la unidad. Aquí, con los disquetes de doble densidad de 5¼ se emplea la tasa de 300 Kbit/segundo: la mayor velocidad de rotación del disco es compensada exactamente por la proporcionalmente mayor velocidad de transferencia, resultando posible de esta manera leer los discos creados en unidades de doble densidad: 300000*0,16666 = 50000 bits de datos, ¡exactamente igual que en las unidades de doble densidad!. Por supuesto, estas unidades giran siempre a 360 r.p.m. y no es posible alterar la velocidad para leer los viejos formatos, como indican otras publicaciones ¡lo que cambia es la tasa de transferencia!. Las controladoras de alta densidad pueden, por lo tanto, emplear velocidades de 300, 500 y (aunque no usada en 5¼) 250 Kbit/seg. Con disquetes de alta densidad de 5¼ y a 500 Kbit/seg caben 500000*0,16666 = 83333 bits por pista (10416 bytes). El GAP 3 que emplea el FORMAT del DOS es de 84 bytes: cada sector ocupa 512+62+84 = 658 bytes, con lo que caben 15. Esto, unido a los 80 cilindros del disco permite almacenar 1200 Kb en el mismo (en estas unidades se accede a los discos de 360K saltando los cilindros de dos en dos).

     Las más modernas unidades de 3½ permitieron mantener la velocidad de 500 Kbit/seg con la velocidad de rotación clásica de 300 r.p.m., sin problemas de fiabilidad, lo que eleva aún más la capacidad. Con ello, los disquetes de alta densidad de 3½ almacenan 500000*0,2 = 100000 bits de datos (12500 bytes) en cada pista. El FORMAT del DOS emplea un amplio GAP 3 de 108 bytes; cada sector ocupa por lo tanto 512+62+108 = 682 bytes, con lo que caben 18 por pista en estas condiciones, lo que genera los conocidos discos de 1440 Kb. Antes de las unidades de alta aparecieron las de doble densidad de 3½: estas emplean una velocidad de 250 Kbit/segundo, con lo que sólo admiten 6250 bytes por pista (los mismos que un disquete de doble densidad de 5¼) y 720 Kb por disco (también emplean un GAP 3 de 80 bytes). Con controladoras de alta densidad se puede seleccionar con estos disquetes la velocidad de 300 Kbit/segundo, lo que permite formatear discos de 3½ y doble densidad con cerca de 1 Mb, sin problemas de fiabilidad. Sin embargo, el FORMAT del DOS y las rutinas de la BIOS sólo soportan en estos discos la velocidad de 250 Kbit/segundo al ser la única que los PC/XT normalmente admiten. Por supuesto, el usuario siempre puede perforar el disco para convertirlo en uno de alta densidad: la calidad de la superficie magnética en los discos de 360K es suficientemente baja para que den errores en las últimas pistas (las más próximas al centro y con menor longitud de circunferencia) al formatearles en alta densidad; sin embargo, en 3½ los fabricantes no se han complicado la vida y es probable que a veces se puedan formatear los discos de doble densidad como de alta sin problemas,  algo que pese a todo no es quizá recomendable.  Las unidades de 3½ detectan el tipo de disco y las perforaciones del mismo sólo sirven para que la disquetera sepa qué velocidad de transferencia emplear (sin embargo, en 5¼ no hay perforaciones y la unidad es capaz de detectar la velocidad apropiada).

+-----------------------------------------+-------------------+------------------+-------------------+------------------+------------------+
|        FORMATOS DE DISCO ESTÁNDAR       | 5¼ Doble Densidad | 5¼ Alta Densidad | 3½ Doble Densidad | 3½ Alta Densidad | 3½ Extra Alta D. |
+-----------------------------------------+-------------------+------------------+-------------------+------------------+------------------+
| Velocidad de rotación (R.P.M.)          |     300/360(*)    |        360       |         300       |        300       |        300       |
| Velocidad de transferencia (bits/seg.)  | 250000/300000(**) |    500.000       |     250.000       |    500.000       |  1.000.000       |
| Esquema de codificación de información  |         MFM       |        MFM       |         MFM       |        MFM       |        MFM       |
| Bytes brutos por pista                  |       6.250       |     10.416       |       6.250       |     12.500       |     25.000       |
| Tamaño de sector en bytes [1]           |         512       |        512       |         512       |        512       |        512       |
| GAP 3 al formatear con FORMAT [2]       |          80       |         84       |          80       |        108       |         80       |
| Bytes que usa el 765 entre sectores [3] |          62       |         62       |          62       |         62       |         62       |
| Bytes ocupados por sector ([1]+[2]+[3]) |         654       |        658       |         654       |        682       |        654       |
| Sectores por pista                      |           9       |         15       |           9       |         18       |         36       |
| Bytes que usa el 765 en inicio de pista |         146       |        146       |         146       |        146       |        146       |
| Bytes aproximados que restan en GAP 4B  |         218       |        400       |         218       |         78       |       1310       |
| Cilindros                               |          40       |         80       |          80       |         80       |         80       |
| Caras o cabezales                       |           2       |          2       |           2       |          2       |          2       |
| Sectores en el disco                    |         720       |       2400       |        1440       |       2880       |       5760       |
| Kbytes por disco                        |         360       |       1200       |         720       |       1440       |       2880       |
+-----------------------------------------+-------------------+------------------+-------------------+------------------+------------------+
                                                                         (*) 300 en unidades de doble densidad y 360 en las de alta densidad
                                                                (**) 250.000 en unidades de doble densidad y 300.000 en las de alta densidad

     Finalmente, los disquetes de extraalta densidad de 3½ trabajan con 1 Mbit/segundo de velocidad de transferencia, con 25000 bytes por pista y 36 sectores: el doble de datos que en alta densidad, pero a un precio mucho más del doble, lo que les ha convertido en un lujo y un fracaso comercial. Existen unidades de 3½ perfeccionadas por medios ópticos que almacenan 20 megabytes por disco, y que también admiten disquetes de 720K y 1.44M (y a menudo, no los de 2.88M). El secreto de estos discos ópticos (flopticals) es la precisión en el posicionamiento del cabezal, lo que permite almacenar cientos de cilindros en lugar de las 80 habituales. También hay unidades ZIP que admiten disquetes (aproximadamente de 3½) con capacidad de 100 Mb ó 1 Gb, pero menos convencionales (están sectorizadas por hardware).

     Los discos normales están formateados con sectores de 512 bytes en todos los casos. Estos sectores son numerados a partir de 1 (y no a partir de 0) en el momento del formateo, y así habrán de ser accedidos en el futuro. En una sola vuelta del disco es factible escribir o leer todos los sectores de una pista si se hace de una vez con el comando apropiado, ya que accediendo de sector en sector podría no dar tiempo a acceder al siguiente sector cuando el anterior acaba de pasar por delante del cabezal, lo que además obligaría a dar una vuelta al disco por cada sector, con un desplome en picado del rendimiento. Lo mismo puede suceder si los sectores están excesivamente próximos debido al empleo de un formato no estándar de más capacidad: normalmente, los GAP 3 que separan los sectores son bastante amplios como para dar tiempo al 765, en las operaciones de escritura, a conmutar entre la escritura de los últimos bytes del sector (junto al CRC que va detrás) y la lectura de los ID del sector siguiente; en caso contrario la operación de escritura de múltiples sectores terminaría con error (sector no encontrado), a no ser que fueran escritos de uno en uno, con la consiguiente ralentización del acceso. Experimentalmente se puede afirmar que el GAP 3 en alta densidad no debería ser inferior a 32, ni tampoco inferior a 40 en doble densidad, lo que parece indicar que la unidad necesita que los sectores estén separados al menos entre 0.5 y 1 ms, respectivamente; aunque estas cifras se pueden rebajar incluso casi a la mitad, esos valores son los mínimos recomendados. En caso de tener que infringir esta regla, la solución sería emplear un interleave distinto del 1:1 habitual: en otras palabras, los sectores pueden ser numerados de manera no consecutiva. Por ejemplo, con 9 sectores, se les puede colocar en la pista, sucesivamente, con los números 1, 6, 2, 7, 3, 8, 4 ,9, 5. Así, entre dos sectores de número consecutivo hay otro, y se gana tiempo para poder pillarlo; este ejemplo en concreto corresponde a un interleave 1:2, ya que hay que dar dos vueltas al disco para poder acceder una vez a toda la pista. Hay casos en que al juntar mucho los sectores e intentar escribir una pista no se produce el error: esto puede ocurrir sobre todo con sectores de más de 512 bytes, ya que cuando el cabezal acaba de acceder a un sector y va a por el siguiente (que acaba de pasar de largo), no encuentra los ID del que va detrás hasta pasado un buen rato; de ahí a volver a encontrarse con el sector buscado puede transcurrir bastante menos de una vuelta del disco y finalmente lo encontraría sin devolver error. Naturalmente, esto sigue sin ser interesante, una vez más, por razones de velocidad. Finalmente señalar que el GAP mínimo para operaciones de lectura multisector es mucho menor que para las operaciones de escritura (bastaría con un GAP de 1 ó 2 bytes), ya que la unidad no pierde tiempo en conmutar entre la escritura del sector y la lectura de IDs del siguiente.

     Un pequeño detalle más: conviene recordar que al formatear una pista, la controladora espera al paso de la marca de índice -el pequeño agujerito del disquete- lo que provoca que si todas las pistas se numeran por igual, en ambas caras del disco están colocados físicamente en la misma posición los mismos números de sector, gracias a esta sincronización, conservando la estructura a lo largo de unos radios imaginarios. Digamos que si el disco es una tarta, al cortar las porciones cada comensal se lleva todos los cilindros del mismo y único sector N que le ha tocado. En la operación habitual del disco, cuando se acaba de acceder a una pista, lo más probable es que haya que continuar en la siguiente (bien en el otro cabezal o en el cilindro adyacente). Esta conmutación de cabezal hace perder cierto tiempo: cuando se acaba de acceder a una pista, el cabezal está al final de la misma y, por consiguiente, muy cerca también del principio (a nadie se le escapa que las pistas son circulares); si se conmuta de cabezal y el disco ya ha girado lo suficiente como para pasar por delante del primer sector de la nueva pista, habrá que volver a dar una vuelta entera. Esto puede suceder si el GAP que hay al final de la pista no es lo suficientemente grande. Y, por desgracia, de hecho sucede con todos los formatos de disco del DOS. Al pasar de una pista a la adyacente, en operaciones de escritura, se pierden unos 18 milisegundos (3 del desplazamiento del cabezal y 15 de espera hasta que éste deje de vibrar) lo que equivale a 1125 bytes en un disco de alta densidad de 3½: ¡unos dos sectores!. Por eso, cuando se acaba con el sector 18 de una pista y se pasa a la siguiente, el cabezal está sobre algún punto del sector 2 ó el 3 y el primer sector que se encuentra es el 3 ó el 4, teniendo que esperar a que pasen otros 15 ó 16 para llegar al 1. La solución a este problema pasa por numerar los sectores, de una pista a otra, deslizando la numeración (técnica conocida como skew o sector sliding):

     1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18    Pista N
    16  17  18   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15    Pista N+1
    13  14  15  16  17  18   1   2   3   4   5   6   7   8   9  10  11  12    Pista N+2

     En el esquema se han trazado sólo tres pistas, pero las siguientes tendrían un tratamiento análogo. Realmente, al conmutar de un cabezal a otro en el mismo cilindro no hace falta deslizar tanto la numeración, ya que es una operación más ágil y con menos retardos. En el ejemplo, experimentalmente se puede determinar que en vez de 3 bastaría con desplazar 2 sectores la numeración. En los discos de 5¼ de alta densidad se pueden recomendar los mismos desplazamientos de numeración. Sin embargo, en los de 5¼ y doble densidad bastaría con desplazar un sector el orden al conmutar de cabezal (y los mismos 3 al cambiar de cilindro). En los de doble densidad de 3½ conviene desplazar un sector la numeración al conmutar de cabezal y 2 al cambiar de cilindro. Por supuesto, estos valores son los más convenientes en general, si bien algún ordenador en concreto podría operar mejor con otra numeración similar a ésta aunque no idéntica. En cualquier caso, numerar todos los sectores de las pistas por igual, que es lo que hacen todas las versiones del FORMAT del DOS (al menos hasta la versión 6.0 del sistema), resulta extremadamente ineficiente y puede reducir a la mitad la velocidad de los disquetes. Algunos buenos formateadores (como FDFORMAT con sus opciones /X e /Y) suelen tener en cuenta estos factores. Por supuesto, esta numeración de los sectores no implica la más mínima pérdida de compatibilidad en los disquetes estándar: lo que sucede es que los creadores del DOS no se han preocupado demasiado hasta ahora de optimizar el rendimiento.

12.6.5 - ACCESO A DISCO CON DMA.

     Los disquetes son gestionados por la BIOS en todas las máquinas empleando el DMA, por medio del canal 2 del 8237. Sin embargo, como veremos en un apartado posterior, es factible realizar las operaciones directamente, sin ayuda del DMA. Al emplear el modo DMA, se produce una interrupción IRQ6 (INT 0Eh) para avisar del término de la operación de disco realizada. Al emplear el DMA conviene tener cuidado con evitar un desbordamiento en el offset 0FFFFh de la página empleada. Por ejemplo, intentar leer o grabar un sector normal de 512 bytes entre las direcciones de memoria 3FF2:0000 y la 3FF2:01FF (direcciones absolutas 3FF20 a la 4011F) resultará fallido al estar implicadas las páginas de DMA 3 y 4, cuando sólo puede estarlo una de las dos. En la práctica, será necesario reservar memoria por importe del doble del tamaño del (o los) sector(es) a ser accedido(s) y hacer cálculos para establecer una dirección de transferencia que coincida dentro de una sola página de DMA. No tener en cuenta este factor es jugar a la lotería con los discos. La BIOS del sistema se encarga de comprobar por software si el buffer facilitado cruza una frontera de DMA antes de realizar las operaciones de E/S, retornando con el error correspondiente en caso afirmativo. Por hardware es imposible detectar esta circunstancia al no producirse errores, pero sí falla la operación: se corrompen zonas de memoria no previstas y el resultado probable es disfunción y/o cuelgue del sistema (a no ser que haya mucha suerte). Sin embargo, cuando el DOS se carga en memoria al principio del arranque, modifica la INT 13h de la BIOS para que esta interrupción nunca devuelva un error debido a este motivo (en cambio, la INT 40h, que es quien realmente controla los disquetes en la inmensa mayoría de los ordenadores AT y que es invocada desde INT 13h, sí puede devolver errores de frontera de DMA).

+-----------------------------------------------------------------------------+
| 765DEBUG 3.1  - UTILIDAD PARA ANALISIS AVANZADO A BAJO NIVEL DE DISQUETES.  |
|                 Programación directa del controlador NEC765 y el DMA 8237.  |
|                 Funcionamiento probado bajo sistemas PC XT, AT, 386 y 486.  |
|                 Soporte para disquetes de 360K, 720K, 1.2M, 1.44M y 2.88M.  |
|                                                                             |
|                            (C) 1992, 1993, 1994 - Ciriaco García de Celis.  |
|                                                                             |
|                                                                             |
|                      F2 - Seleccionar unidad/densidad y resetear.           |
|                      F3 - Recalibrar cabezal (necesario tras F2).           |
|                                                                             |
|                      F4 - Cambiar de cabezal.                               |
|                      F5 - Posicionar cabezal.                               |
|                      F6 - Leer ID's.                                        |
|                      F7 - Leer sector.                                      |
|                      F8 - Escribir sector.                                  |
|                      F9 - Formatear pista.                                  |
|                     F10 - Conmutar MF/MFM.                                  |
|                     ESC - Salir                                             |
|                                                                             |
|                                                                             |
|                 Unidad A:  500 Kbit/seg en MFM - Cilindro  0 y Cabezal 0    |
|                                                                             |
|                                                                             |
|     Elige una opción: _                                                     |
+-----------------------------------------------------------------------------+
Figura 12.6.5.1                                 PANTALLA PRINCIPAL DEL PROGRAMA

     El siguiente programa de ejemplo ha sido realizado íntegramente en Borland C (compilable también sin errores en Turbo C 2.0) y permite practicar al lector con la operación a bajo nivel del disco. Se pueden leer y escribir sectores (con tamaños normales o no), formatear pistas, leer los ID de una pista, y todas las operaciones auxiliares necesarias (seleccionar unidad, velocidad de transferencia, recalibrar, seleccionar cabezal, posicionar cabezal, elegir MF/MFM). La opción de leer ID's es especialmente útil para analizar discos con protecciones anticopia; se trata además de una tarea inevitable que ha de realizar necesariamente cualquier copión, como paso previo a la duplicación del disquete. En esta opción se utiliza una interesante rutina de temporización de alta precisión, empleando el 8254, para poder medir con exactitud los milisegundos de disco que ocupa cada sector en la pista y poder hacerse una idea de cómo está organizada y aprovechada. El formateo también es especialmente versátil,   ya que permite editar,   sin lujos pero con eficacia, los bytes de los sectores propuestos por defecto -los más razonables por otra parte- antes de enviarlos al controlador. Este programa es un útil banco de pruebas para medir la fiabilidad de técnicas de formateo especial, para idear y probar métodos de protección anticopia y, en general, para aprender sobre el funcionamiento a bajo nivel de los discos. El dato de la velocidad de transferencia no es relevante por lo general en los PC/XT. La selección incorrecta de una sola opción puede provocar que el programa falle, aunque al cabo de unos segundos se recupera el control. Las dos primeras opciones del menú no son obligatorias; pero conviene seleccionarlas al principio y, en general, cada vez que se cambie de disco. Una línea inferior informa permanentemente de los principales parámetros activos, si bien no conviene creer ciegamente en ella. Por ejemplo, si se ha intentado posicionar el cabezal en el cilindro 120 de un disco formateado, y luego se le vuelve a posicionar en el 70, en esa línea aparecerá el valor 70 aunque al leer los ID podríamos descubrir que está realmente sobre el cilindro 31, ya que esa unidad no soporta más de 82 cilindros (numerados de 0 a 81) y no pudo pasar del 81 cuando se le ordenó ir al 120. En este ejemplo particular, lo más aconsejable después sería recalibrar, ya que el programa cree que está sobre el cilindro 70 y las opciones de leer y escribir sector fallarán; ya que no preguntan el número de cilindro y emplean el que se supone activo al enviar el comando al controlador.

+----------------------------------------------------------------------------------+
|  Sector a leer: 1                                                                |
|                                                                                  |
|                                                                                  |
| Tamaño de sector:                                                                |
|   0 -> 1-128 bytes                                                               |
|   1 ->  256  bytes                                                               |
|   2 ->  512  bytes                                                               |
|   3 -> 1024  bytes                                                               |
|   4 -> 2048  bytes                                                               |
|   5 -> 4096  bytes                                                               |
|                                                                                  |
|    Elige: 2                                                                      |
|                                                                                  |
| Resultado de la operación:                                                       |
|                                                                                  |
|   [ST0=0x01] [ST1=0x00] [ST2=0x00]                                               |
|   [Cilindro 1] [Cabezal 0] [Sector 1] [Tamaño 2]                                 |
|                                                                                  |
|   Pulsa una tecla para ver el sector [ESC=salir].                                |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|                                                                                  |
|                                                                                  |
|                                                                                  |
|   0000:  EB 3C 90 4D 53 44 4F 53 - 35 2E 30 00 02 01 01 00    .<ÉMSDOS5.0.....   |
|   0010:  02 E0 00 40 0B F0 09 00 - 12 00 02 00 00 00 00 00    ...@.=..........   |
|   0020:  00 00 F8 04 00 00 29 EC - 1D 64 3C 4E 4F 20 4E 41    ..'...)..d<NO NA   |
|   0030:  4D 45 20 20 20 20 46 41 - 54 31 36 20 20 20 FA 33    ME    FAT16   .3   |
|   0040:  C0 8E D0 BC 00 7C 16 07 - BB 78 00 36 C5 37 1E 56    +Ä++.|..+x.6+7.V   |
|   0050:  16 53 BF 3E 7C B9 0B 00 - FC F3 A4 06 1F C6 45 FE    .S+>|+..n.ñ...E.   |
|   0060:  0F 8B 0E 18 7C 88 4D F9 - 89 47 02 C7 07 3E 7C FB    .ï..|êM.ëG.+.>|.   |
|   0070:  CD 13 72 79 33 C0 39 06 - 13 7C 74 08 8B 0E 13 7C    =.ry3+9..|t.ï..|   |
|   0080:  89 0E 20 7C A0 10 7C F7 - 26 16 7C 03 06 1C 7C 13    ë. |á.|=&.|...|.   |
|   0090:  16 1E 7C 03 06 0E 7C 83 - D2 00 A3 50 7C 89 16 52    ..|...|â+.úP|ë.R   |
|   00A0:  7C A3 49 7C 89 16 4B 7C - B8 20 00 F7 26 11 7C 8B    |úI|ë.K|+ .=&.|ï   |
|   00B0:  1E 0B 7C 03 C3 48 F7 F3 - 01 06 49 7C 83 16 4B 7C    ..|..H=...I|â.K|   |
|   00C0:  00 BB 00 05 8B 16 52 7C - A1 50 7C E8 92 00 72 1D    .+..ï.R|íP|.Æ.r.   |
|   00D0:  B0 01 E8 AC 00 72 16 8B - FB B9 0B 00 BE E3 7D F3    *..¼.r.ï.+..+.}.   |
|   00E0:  A6 75 0A 8D 7F 20 B9 0B - 00 F3 A6 74 18 BE 9E 7D    ªu.ì +....ªt.+.}   |
|   00F0:  E8 5F 00 33 C0 CD 16 5E - 1F 8F 04 8F 44 02 CD 19    ._.3+=.^.Å.ÅD.=.   |
|                                                                                  |
|                   Bytes 0000-0255 del sector (1/2)                               |
|                   Utiliza los cursores [ESC=salir]                               |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|                                                                                  |
|                                                                                  |
|                                                                                  |
|   0100:  58 58 58 EB E8 8B 47 1A - 48 48 8A 1E 0D 7C 32 FF    XXX..ïG.HHè..|2    |
|   0110:  F7 E3 03 06 49 7C 13 16 - 4B 7C BB 00 07 B9 03 00    ....I|..K|+..+..   |
|   0120:  50 52 51 E8 3A 00 72 D8 - B0 01 E8 54 00 59 5A 58    PRQ.:.r+*..T.YZX   |
|   0130:  72 BB 05 01 00 83 D2 00 - 03 1E 0B 7C E2 E2 8A 2E    r+...â+....|..è.   |
|   0140:  15 7C 8A 16 24 7C 8B 1E - 49 7C A1 4B 7C EA 00 00    .|è.$|ï.I|íK|...   |
|   0150:  70 00 AC 0A C0 74 29 B4 - 0E BB 07 00 CD 10 EB F2    p.¼.+t)+.+..=...   |
|   0160:  3B 16 18 7C 73 19 F7 36 - 18 7C FE C2 88 16 4F 7C    ;..|s..6.|x+ê.O|   |
|   0170:  33 D2 F7 36 1A 7C 88 16 - 25 7C A3 4D 7C F8 C3 F9    3+.6.|ê.%|úM|'+.   |
|   0180:  C3 B4 02 8B 16 4D 7C B1 - 06 D2 E6 0A 36 4F 7C 8B    ++.ï.M|o.+..6O|ï   |
|   0190:  CA 86 E9 8A 16 24 7C 8A - 36 25 7C CD 13 C3 0D 0A    +å.è.$|è6%|=.+..   |
|   01A0:  45 72 72 6F 72 2C 20 64 - 65 20 64 69 73 63 6F 20    Error, de disco    |
|   01B0:  64 65 20 73 69 73 74 65 - 6D 61 0D 0A 52 65 65 6D    de sistema..Reem   |
|   01C0:  70 6C 61 63 65 20 79 20 - 70 72 65 73 69 6F 6E 65    place y presione   |
|   01D0:  20 63 75 61 6C 71 75 69 - 65 72 20 74 65 63 6C 61     cualquier tecla   |
|   01E0:  0D 0A 00 49 4F 20 20 20 - 20 20 20 53 59 53 4D 53    ...IO      SYSMS   |
|   01F0:  44 4F 53 20 20 20 53 59 - 53 00 00 00 00 00 55 AA    DOS   SYS.....U¬   |
|                                                                                  |
|                   Bytes 0256-0511 del sector (2/2)                               |
|                   Utiliza los cursores [ESC=salir]                               |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+
Figura 12.6.5.2                                                 LECTURA DE UN SECTOR

     Al principio del programa se asignan valores por defecto a las variables, se establece la velocidad de transferencia en 500 Kbit/seg y se reserva memoria para almacenar un sector. Como se vio anteriormente, hay que asegurar que el buffer no cruza una frontera de DMA, por lo que en la práctica se reserva el doble de la memoria necesaria y se asigna el puntero de tal manera que esto no suceda en ningún caso. El programa consta de un menú desde el que se accede a las diversas opciones que desembocan finalmente en funciones independientes. La función seleccionar() permite elegir la unidad activa, reseteándola y enviando el comando specify al FDC.

     La función recalibrar() envía este comando al FDC y lo repite si falla, por si estaba sobre un cilindro superior al 77; en esta función y en las restantes, para detectar el fin de la operación se espera la llegada de la interrupción de disco correspondiente (IRQ 6, ligada a INT 0Eh). La BIOS se encarga en esta interrupción de activar el bit más significativo de la posición 40h:3Eh. La función esperar_int() espera la llegada de la interrupción comprobando dicho bit durante un par de segundos antes de considerar que la operación ha fallado, devolviendo después dicho bit a 0. Realmente, aunque haya un error la interrupción debe llegar y el comando ha de finalizar. Sin embargo, el FDC es a veces demasiado flexible: por ejemplo, si la portezuela de la unidad (en 5¼) está abierta y hay un disco introducido, se puede quedar esperando indefinidamente. Además, en general, en la programación a bajo nivel es conveniente no hacer nunca bucles infinitos para esperar a que suceda algo. Tras el comando de recalibrado hay que ejecutar el de lectura de estado de interrupciones, cuyo resultado es además impreso en pantalla durante 1,5 segundos para dar tiempo a leerlo sin tener que pulsar teclas (es muy poca información y se puede leer en menos de un segundo...).

     La función posicionar() lleva el cabezal sobre el cilindro solicitado. Si se está trabajando con una velocidad de 300 Kbit/seg, correspondiente normalmente a un disco de 5¼ y doble densidad (360K), se pregunta al usuario si la unidad es de 80 cilindros (1.2M) y se le pide que confirme que el disco es de 360K. En ese caso, el número de cilindro será multiplicado por dos al enviar el comando seek al FDC, ya que es un disco formateado con 40 pistas. Al final se ejecuta nuevamente el comando de lectura de estado de interrupciones, imprimiendo el resultado y haciendo una pausa para que de tiempo a leerlo, aunque si se omitiera este paso y la siguiente operación fuera de escritura al menos habría que esperar 15 milisegundos para dar tiempo al cabezal a asentarse y dejar de vibrar. Realmente, en este programa ni eso haría  falta,  ya que no hay humano tan rápido que en menos de 15 ms después de haber escogido la opción de posicionar cabezal pueda elegir la de escribir sector en el menú principal. Pero en otros programas, donde se posicione repetidamente el cabezal y se acceda al disco en escritura repetitivamente, conviene no olvidar hacer la pausa. Bueno, si se olvida, no sucede nada: sólo se podría producir algún error al escribir que no se detectaría hasta una posterior lectura. Lo malo es que estos errores son esporádicos y resulta muy difícil localizar su origen.

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [   10.77]  10.77     9     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   21.53]  10.76    10     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   32.31]  10.78    11     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   43.07]  10.76    12     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   53.85]  10.78    13     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   64.63]  10.78    14     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   75.52]  10.89    15     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   86.30]  10.77    16     512 (  2)      0       0    0x00  0x00  0x00     |
|     [   97.07]  10.77    17     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  111.31]  14.24    18     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  122.07]  10.76     1     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  132.85]  10.78     2     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  143.61]  10.76     3     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  154.38]  10.77     4     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  165.15]  10.77     5     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  175.93]  10.78     6     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  186.69]  10.77     7     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  197.46]  10.77     8     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  208.24]  10.78     9     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  219.00]  10.76    10     512 (  2)      0       0    0x00  0x00  0x00     |
|     [  229.78]  10.79    11     512 (  2)      0       0    0x00  0x00  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [  399.32] 399.32    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [  798.94] 399.62    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 1198.43] 399.50    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 1598.09] 399.66    12     512 (  2)      0       0    0x40  0x04  0x00     |
|     [ 1997.53] 399.44    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 2396.95] 399.41    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 2796.40] 399.45    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 3196.00] 399.61    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 3595.62] 399.61    12     512 (  2)      0       0    0x40  0x04  0x00     |
|     [ 3995.22] 399.61    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 4394.62] 399.40    12     512 (  2)      0       0    0x40  0x04  0x00     |
|     [ 4794.18] 399.56    12     512 (  2)      0       0    0x40  0x04  0x00     |
|     [ 5193.60] 399.42    12     512 (  2)      0       0    0x40  0x04  0x00     |
|     [ 5593.10] 399.50    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 5992.69] 399.59    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 6392.16] 399.47    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 6791.64] 399.48    12     512 (  2)      0       0    0x40  0x04  0x00     |
|     [ 7191.33] 399.70    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 7590.84] 399.50    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 7990.23] 399.40    12     512 (  2)      0       0    0x40  0x01  0x00     |
|     [ 8389.74] 399.51    12     512 (  2)      0       0    0x40  0x01  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+
Figura 12.6.5.3                               LECTURAS CORRECTA E INCORRECTA DE ID's

     Las funciones leer_sector() y escribir_sector() son muy parecidas. La principal diferencia es que la primera muestra el sector leído (ver figura 12.6.5.2) y la segunda tiene que preguntar el byte con que rellenará el sector escrito, ya que no permite editarlo. Antes de leer el sector se rellena el buffer en memoria con la signatura 5AA5h. Tras la lectura, el sector es mostrado -incluso si se produjo error- aunque si el usuario observa que contiene precisamente 5AA5h podrá deducir que elerror iba muy en serio. Hay casos en que con error y todo puede ser interesante ver el sector, como luego veremos. La lectura y escritura de los sectores se realiza por DMA, el cual es programado por prepara_dma().

     La función leer_id() envía 22 veces dicho comando al FDC, para leer los ID (los 4 bytes con que se formateó cada sector) y la información de estado (registros ST0..ST2). Probablemente no habrá más de 21 sectores en una pista, por lo que será posible echar un vistazo detallado a la misma. El primer sector en aparecer no es el 1 ni el de número más bajo: sencillamente, el primero en pasar por el cabezal al ejecutar el comando; como la unidad estaba girando con antelación y el usuario elige la opción cuando quiere, el primer sector visualizado será cualquier sector de la pista aleatoriamente. Si hubiera más de 21 sectores en la pista, se visualizarían sólo los 21 primeros en pasar delante del cabezal. Resulta interesante saber cuánto tiempo transcurre entre el paso de un sector y otro, lo que permite conocer su tamaño real (interesante en discos con protección anticopia) y también ensayar nuevos formatos de disco. Por ejemplo, si se formatean más sectores de los que caben en una pista, el comando de formatear termina siempre con éxito, pero alguno de los últimos sectores habrá machacado a los primeros, y la manera más sencilla de verlo es examinando los ID a ver si están todos. De hecho, entre el último sector de la pista y el primero debería existir una mayor separación que entre otros dos sectores cualquiera, debido a los GAP ubicados al final de la pista y al principio de la misma (que conviene no reducir demasiado). Para medir el tiempo, se programa el 8254 (u 8253 en los PC/XT) con una cuenta 0xFFFF. A partir de ese momento, se espera que llegue la interrupción de disco y se comprueba si el contador se ha decrementado hasta 0 y se ha vuelto a recargar con 0xFFFF: en ese caso, la variable cnth se incrementa para indicar que han pasado 65535/1193180 segundos más; si llegara a valer más de 8 se abortaría el proceso al considerar que la interrupción tarda demasiado en llegar (más de 0,4 segundos en los que el disco más lento ya ha dado dos vueltas). Tras el final de cada comando de lectura de ID, se recarga inmediatamente la cuenta inicial (el valor 0xFFFF) en el contador 2, por el procedimiento de bajar y subir la línea GATE del mismo, con objeto de que empiece a contar el tiempo para el próximo sector desde ya mismo. Se lee la información que devuelve el FDC pero no se imprime por problemas de velocidad, sino que se almacena en una matriz. La variable cnth y el último valor de cuenta leído del 8254 permiten determinar con precisión milimétrica el tiempo que ha pasado desde el envío del comando de lectura de ID's hasta la obtención del resultado. El primer dato de tiempo leído es incorrecto por doble motivo: por un lado, el cabezal podía estar en medio de un sector cuando se envió el comando y el tiempo medido no sería la longitud del sector anterior sino de medio sector anterior; por otro lado, la cuenta es recargada (cambio de la línea GATE) al final de cada comando en lugar de al principio, por razones de precisión. Por ello, se imprimirán los resultados de las 21 últimas muestras, descartando la primera. En la figura 12.6.5.3 hay dos ejemplos de lectura de ID, de la primera pista de un disquete de 1.44M creado por el FORMAT del DOS. En el primero el resultado es correcto; en el segundo, la velocidad seleccionada era incorrecta (no los 500 Kbit/seg necesarios) y el FDC no ha podido encontrar los sectores, teniendo además que dar dos vueltas al disco (200 ms en cada una de ellas). Si no hubiera disquete o la portezuela estuviera abierta, al cabo de un minuto y medio aparecería una pantalla con datos de tiempo N.D. (no determinado) y todos los demás bytes con ?? para indicar el error. Resulta increíble la precisión media de la medida: 399,5 ms frente a los 400 reales: una desviación media de ¡0,5 milisegundos!, si bien esto dependerá del ordenador: cuanto más rápido, más exacta resulta la medida.

+----------------------------------------------------------------------------------+
|                                                                                  |
|                                                                                  |
| Tamaño de sector:                                                                |
|   0 ->  128 bytes                                                                |
|   1 ->  256 bytes                                                                |
|   2 ->  512 bytes                                                                |
|   3 -> 1024 bytes                                                                |
|   4 -> 2048 bytes                                                                |
|   5 -> 4096 bytes                                                                |
|                                                                                  |
|    Elige: 0                                                                      |
|                                                                                  |
| Número de sectores: 25                                                           |
|                                                                                  |
| Valor para el GAP 3: 50                                                          |
|                                                                                  |
| Byte para inicializar sectores: 65                                               |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
| Puntualizaciones sobre el formateo:                                              |
|                                                                                  |
|   He establecido por defecto una tabla con los cuatro                            |
| bytes que hay que enviar al controlador, por cada uno                            |
| de los sectores de la pista, que están numerados:                                |
|                                                                                  |
|    1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20 |
|   21  22  23  24  25                                                             |
|                                                                                  |
|   Puedes elegir lo siguiente:                                                    |
|                                                                                  |
|  1  - Introducir tú los 4 bytes de un sector.                                    |
|  2  - Modificar un cierto byte en todos los sectores.                            |
| ESC - Dejar las cosas como están ahora.                                          |
|                                                                                  |
|   Elige opción.                                                                  |
|                                                                                  |
| Sector a alterar: 6                                                              |
| Nº Cilindro (anterior=0): 0                                                      |
| Nº cabezal (anterior=0): 0                                                       |
| Nº sector (anterior=6): 6                                                        |
| Tamaño sector (anterior=0): 1                                                    |
| ¿De acuerdo (S/N)?                                                               |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
| Resultado de la operación:                                                       |
|                                                                                  |
|   [ST0=0x01] [ST1=0x00] [ST2=0x00]                                               |
|   [Cilindro 65] [Cabezal 1] [Sector 0] [Tamaño 0]                                |
|                                                                                  |
| Formateo correcto. Pulsa una tecla.                                              |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [    6.25]   6.25    19     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   12.52]   6.26    20     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   18.77]   6.26    21     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   25.03]   6.26    22     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   31.30]   6.27    23     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   37.56]   6.26    24     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   50.42]  12.86    25     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   56.68]   6.26     1     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   62.93]   6.25     2     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   69.19]   6.26     3     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   75.46]   6.27     4     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   81.72]   6.26     5     128 (  0)      0       0    0x01  0x00  0x00     |
|     [   87.98]   6.26     6     256 (  1)      0       0    0x01  0x00  0x00     |
|     [   94.25]   6.27     7     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  100.51]   6.26     8     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  106.77]   6.26     9     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  113.03]   6.26    10     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  119.28]   6.26    11     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  125.55]   6.26    12     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  131.81]   6.26    13     128 (  0)      0       0    0x01  0x00  0x00     |
|     [  138.07]   6.26    14     128 (  0)      0       0    0x01  0x00  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+
Figura 12.6.5.4                                                FORMATEO DE UNA PISTA

     La función formatear_pista() pregunta los parámetros básicos (número de sectores, tamaño, GAP y byte de inicialización) y genera una tabla con los 4 bytes que hay que enviar al FDC por cada sector. Sin embargo, permite al usuario editar rudimentariamente dicha tabla con la función editar_tabla_fmt(), para permitir a éste ensayar trucos, ya que los valores propuestos por defecto son por lo general los más convenientes. En esos 4 bytes que hay por cada sector se almacenan el número de cilindro, el de cabezal, el número de sector y el tamaño. En la función de edición se permite cambiar los bytes de un sólo sector, o cambiar uno de los 4 bytes en todos los sectores. Estos 4 bytes identifican cada sector y son comparados con los que se envían en el futuro comando de lectura o escritura de sector, debiendo coincidir plenamente para que el FDC encuentre el sector. El número de cilindro y el de cabezal suelen coincidir -y así son propuestos por defecto- con el cilindro y el cabezal en que esté dicho sector; cambiar esto puede ser interesante en técnicas de protección de información, ya que el sector desaparece pero realmente sigue estando ahí: la diferencia es que a la hora de leerlo hay que indicar al FDC no el cilindro real sobre el que está posicionado el cabezal sino el número de cilindro y cabezal que se programaron al formatear el sector, que pueden ser cualquier otro. Este programa, a la hora de leer los sectores no pregunta el número de cilindro ni cabezal -para ahorrar tiempo- por lo que no permite verificar esta propiedad, pero con una pequeña y sencilla modificación el lector podría comprobarlo por sí mismo. Lo que sí puede resultar más interesante es cambiar el número de sector propuesto por defecto o, mejor aún: su tamaño. Al formatear la pista, el tamaño de los sectores es asignado al enviar el comando de formateo al FDC: todos los sectores tendrán dicho tamaño, con independencia del tamaño particular que se asigne al enviar los 4 bytes específicos. En otras palabras, si se programa un tamaño 2 (de 512 bytes) en el comando de formateo, todos los sectores serán de 512 bytes, aunque alguno esté definido como de 1024, de 256 bytes,... en el 4º byte de información enviado por cada sector al FDC. Por tanto, ¿Para que sirve este byte?: una vez más, para posibilitar la lectura. Si un sector está programado con tamaño 3 (1024 bytes) habrá de ser leído indicando tamaño 3. Si era de 512 bytes, lo que sucede es que además del sector se leen, ni más ni menos, los GAPs que van detrás, los ID's e incluso parte del siguiente sector; por supuesto que se produce un lógico error de CRC al leer, pero los datos leídos son correctos. La figura 12.6.5.4 constituye un ejemplo de formateo: en un disquete de 360K se colocan 25 sectores de 128 bytes con un GAP 3 de 50 bytes, rellenándolos al formatear con el byte 65 (41h, código ASCII de la A). Teniendo en cuenta los 62 bytes que el FDC añade entre sectores en MFM, (128+62+50)*25=6000, por debajo del límite de 6250 en este tipo de disquetes. Los 4 bytes del sector 6 resultan modificados para asignarle un tamaño 1 (256 bytes), aunque el sector es realmente de 128 bytes. La posterior lectura de ID's demuestra cómo ha quedado la pista, si bien sólo se pueden ver en una pantalla los ID de 21 sectores. En la figura 12.6.5.5 se intenta leer dicho sector y, pese al error de CRC, resulta evidente que es bien leído (junto con todo lo que va detrás). La última línea del volcado hexadecimal es el inicio del siguiente sector de la pista. El lector puede verificar que el esquema del final del apartado 12.6.1 es rigurosa y milimétricamente cierto: todos los GAPs, ID y bytes introducidos por el FDC entre sectores aparecen claramente reflejados en la figura. Por supuesto, una posterior escritura del sector 6 pisaría el 7. De ahí que, anécdotas a parte, no suele resultar muy útil generalmente hacer este tipo de maniobras... ¿o tal vez si?.

+----------------------------------------------------------------------------------+
| Sector a leer: 6                                                                 |
|                                                                                  |
|                                                                                  |
| Tamaño de sector:                                                                |
|   0 -> 1-128 bytes                                                               |
|   1 ->  256  bytes                                                               |
|   2 ->  512  bytes                                                               |
|   3 -> 1024  bytes                                                               |
|   4 -> 2048  bytes                                                               |
|   5 -> 4096  bytes                                                               |
|                                                                                  |
|    Elige: 1                                                                      |
|                                                                                  |
| Resultado de la operación:                                                       |
|                                                                                  |
|   [ST0=0x41] [ST1=0x20] [ST2=0x20]                                               |
|   [Cilindro 0] [Cabezal 0] [Sector 6] [Tamaño 1]                                 |
|                                                                                  |
| Error de lectura (el sector puede estar mal leído).                              |
| Nota: el buffer de lectura contenía el patrón 5AA5.                              |
|   Pulsa una tecla para ver el sector [ESC=salir].                                |
|                                                                                  |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|                                                                                  |
|                                                                                  |
|                                                                                  |
|   0000:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0010:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0020:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0030:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0040:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0050:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0060:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0070:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|   0080:  6B 70 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E    kpNNNNNNNNNNNNNN   |
|   0090:  4E 4E 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E    NNNNNNNNNNNNNNNN   |
|   00A0:  4E 4E 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E    NNNNNNNNNNNNNNNN   |
|   00B0:  4E 4E 4E 4E 00 00 00 00 - 00 00 00 00 00 00 00 00    NNNN............   |
|   00C0:  A1 A1 A1 FE 00 00 07 00 - 40 8B 4E 4E 4E 4E 4E 4E    ííí.....@ïNNNNNN   |
|   00D0:  4E 4E 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E    NNNNNNNNNNNNNNNN   |
|   00E0:  00 00 00 00 00 00 00 00 - 00 00 00 00 A1 A1 A1 FB    ............ííí.   |
|   00F0:  41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41    AAAAAAAAAAAAAAAA   |
|                                                                                  |
|                   Bytes 0000-0255 del sector (1/1)                               |
|                   Utiliza los cursores [ESC=salir]                               |
|                                                                                  |
|                                                                                  |
|                                                                                  |
+----------------------------------------------------------------------------------+
Figura 12.6.5.5                                 LECTURA DEL SECTOR DE TAMAÑO TRUCADO

     La función mostrar_resultados() es invocada desde las anteriores, con objeto de leer los 7 bytes que devuelve el FDC al término de los principales comandos e imprimirles en pantalla. La función mostrar_sector() enseña en pantalla el volcado hexadecimal del buffer donde se leen los sectores, en páginas de 256 bytes, teniendo en cuenta el tamaño de los mismos y permitiendo cierta movilidad.

     La función motor_on() arranca el motor de la unidad si aún no estaba en marcha, ajustando al valor máximo la variable que indica cuándo se detendrá, con objeto de evitarlo en lo posible. Al menos estará girando durante 14 segundos en el peor de los casos. La función motor_off() ajusta dicha variable para que el motor se pare en unos 3 segundos. La función outfdc() envía bytes al FDC pero sin esperar más de 440 ms en caso de que éste, por cualquier error, no esté dispuesto a recibirlos. Su recíproca infdc() lee un byte del FDC considerando un fracaso la operación si éste no responde en menos de 440 ms (en estos casos devuelve un valor negativo para que la función que llama advierta el error). La función esperar_int() ya fue comentada anteriormente. Por último, la función prepara_dma() programa el 8237 para transferir el número de bytes indicado, en el modo apropiado (lectura/escritura) y en la dirección del buffer empleado.


12.6.6 - LECTURA Y ESCRITURA DE SECTORES DE DISCO SIN DMA.

     Si bien lo normal es emplear el DMA para realizar los accesos a disco, ello no es estrictamente necesario (excepto en los auténticos PS/2): generalmente también se puede acceder enviando directamente los bytes al FDC, aunque sería más útil emplear el DMA (la CPU no tendría tiempos muertos de espera para mover los bytes). Realmente, bajo DOS da lo mismo acceder con el DMA que sin el, ya que aún cuando se emplea el DMA ¡la pobre CPU se queda esperando a que llegue la interrupción que indica el final de la operación!. La única ventaja real de utilizar el DMA, que motivó su uso por parte de los programadores de IBM, es que el contador de hora de la BIOS sigue avanzando (y el reloj no se atrasa), mientras que sin el DMA se pararía al tener que inhibir las interrupciones en el momento crítico de la transferencia del sector, con objeto de no perder datos. En otros sistemas operativos multitarea, el DMA permite a la CPU continuar trabajando (perdiendo sólo los ciclos estrictamente necesarios para la transferencia) a la par que es realizada la operación de disco: aunque el rendimiento global del sistema se degrada durante la operación, al menos no se detienen todos los procesos.

     El siguiente programa de ejemplo, realizado íntegramente en ensamblador, permite leer y escribir sectores de disco aislados en el formato MFM habitual. Soporta las unidades A: y B:, así como discos y disqueteras de todos los formatos y densidades -incluidos los no estándar-. Se preguntan todos y cada uno de los parámetros necesarios, dando algunas pautas para ayudar. Es importante responder correctamente, aunque el control de errores suele recuperar los fallos, sin dejar bloqueado el ordenador, en un plazo de tiempo razonable. Esta utilidad se basa en un menú principal donde se tiene acceso a las diversas opciones, que desembocan en las rutinas de bajo nivel que controlan el disco. No describiremos las rutinas encargadas de tomar datos del teclado ni tampoco las de impresión en pantalla, bastante obvias. Sin embargo, daremos un ligero repaso a las subrutinas encargadas de controlar el disco.

     El procedimiento init_drv enciende el motor de la disquetera y resetea el FDC a través de la subrutina reset_drv, esperando después a que el motor alcance un régimen de rotación adecuado. En reset_drv se selecciona además el modo NO DMA en el registro de salida digital, se espera por la interrupción que indica el fin del reset y se envía el comando specify al FDC; también se establece la velocidad de transferencia apropiada para el tipo de disquete a ser accedido. El procedimiento recalibrar ejecuta dicho comando del FDC hasta un máximo de dos veces en caso de fallo, entre otros motivos para prevenir que el cabezal estuviera inicialmente en una pista superior a la 77. Tanto en este procedimiento como en el seek_drv se detecta el inicio de la fase de resultados esperando la pertinente interrupción de disco (en la rutina espera_int). Debido a que las interrupciones no llegan cuando está activo el modo NO DMA en el registro de salida digital, por algún oscuro motivo que desconozco, es preciso establecer momentáneamente el modo DMA a través del bit 3 de dicho registro (rutina habilita_int) y volverlo a desactivar una vez que llega la interrupción; realmente, aún seleccionando esta modalidad, el DMA no será empleado ya que no se utiliza en los comandos de recalibración ni en el de posicionamiento del cabezal. En esta última rutina se tiene en cuenta el caso especial que supone un disquete de 40 pistas en una unidad de 80, multiplicándose entonces por 2 el número de cilindro antes de enviarlo al FDC.

     La rutina sector_io es la encargada de leer y escribir los sectores de disco. Tras enviar el comando al FDC, se espera que éste encuentre el sector y seguidamente se pasa a leer/escribir el mismo directamente, aunque en lugar de emplear las rutinas E/S habituales (fdc_read y fdc_write) se realiza el proceso de manera directa para acelerarlo. Más que para acelerarlo, para que no nos pille: la velocidad es aquí crítica (el proceso se realiza con las interrupciones apagadas) ya que cada 16-32 microsegundos hay que transferir un byte entre la CPU y el FDC y dormirse en los laureles supondría un error irrecuperable. Si se está escribiendo un sector y se produce un fallo, es fácil detectarlo (el FDC deja de recibir datos e intenta enviar los bytes de la fase de resultados) pero en la lectura de sectores serían leídos dichos resultados confundidos como datos del sector, aunque al terminar el comando (y bajar el bit CB del registro de estado) se detectaría afortunadamente el final de la operación y se podría suponer que los últimos 7 bytes leídos no eran del sector sino la fase de resultados. En general, si el usuario ha indicado bien todos los parámetros y el disquete no está defectuoso, no habrá problemas. Estas rutinas de lectura de sectores no están diseñadas de manera tolerante a fallos, ya que realizan saltos condicionales comprobando los bits del registro de estado, que en caso de quedarse congelados y no cambiar supondrían un cuelgue del sistema. Sin embargo, añadir controles de timeout alargaría los tiempos de ejecución y podría provocar, si no se tiene cuidado, que los PC/XT más lentos no fueran bastante potentes para acceder al disco con la suficiente rapidez. Además, la mejor técnica para controlar los timeout es, indiscutiblemente, la monitorización de los ciclos de refresco de la memoria dinámica de los AT (ese bit del puerto 61h que cambia 66287 veces por segundo): en los PC/XT sería más complicado...

     Por último, las rutinas fdc_read y fdc_write se encargan de la comunicación CPU-FDC en ambos sentidos, aunque aquí sí se han establecido unos rudimentarios controles de timeout, de esos que tardan más tiempo en recuperar el control en las máquinas más lentas. De ahí que estas subrutinas no sean empleadas desde sector_io, por razones de velocidad.

     Acceder a disco sin DMA es más incómodo y problemático que hacerlo a través del DMA, y no ofrece absolutamente ninguna ventaja adicional, a no ser que el 8237 esté averiado en el ordenador. De hecho, yo personalmente dejé de utilizar durante algún tiempo el DMA en los accesos de disco (me hice un controlador especial que además me ayudó a subir nota en una asignatura), creyendo que los errores en la transferencia de datos en mis disqueteras se debían a este integrado. Sin embargo, finalmente averigué que la causa estaba en los SIPPs de memoria un tanto flojos (por fortuna, resulta que un amigo mío sí tenía estropeado el DMA de verdad en las operaciones de escritura, y ese driver le vino muy bien para poder escribir en sus disquetes). Anécdotas aparte, este programa es meramente educativo y no un modelo a seguir.


12.6.7 - PROGRAMACION AVANZADA DEL CONTROLADOR DE DISQUETES: 2M 3.0

     Hasta ahora hemos descrito todo lo necesario para poder programar la controladora de disquetes. Ahora aplicaremos dicha información a un caso práctico real, con un programa. Ciertas aplicaciones comerciales de backup ya emplean formatos de disco de más capacidad para almacenar los datos, además de manera comprimida. Sin embargo, estos disquetes no pueden ser empleados directamente por el DOS. Por el contrario, la utilidad que desarrollaremos, 2M, es un programa residente que permite gestionar disquetes con sectores de más de 512 bytes e, incluso, con sectores de distinto tamaño en las pistas. Este último formato obtendrá algo más de capacidad, pero menos velocidad y fiabilidad. En 3½", los disquetes más comunes de 1.44M (1440K) se podrán formatear a 1804K y 1886K, respectivamente. Los de 720K alcanzarán los 984/1066K. En 5¼" los de 1.2M pasan a 1476/1558K y los de 360K a 820/902K. Los formatos de 1886K, 1066K y 1558K no pueden ser reproducidos por la versión de enero de 1992 del poderoso copión COPYWRITE; el de 902K sí es duplicado en algunos ordenadores, aunque a veces algunas pistas quedan mal. Esto no es problema para el usuario normal, que podrá hacer DISKCOPY (si 2M está instalado en memoria) hacia un disco destino ya formateado. Para formatear estos nuevos disquetes se empleará un pequeño programa escrito en C (2MF.C) que se limitará a llamar a las funciones de INT 13h reforzadas por 2M; dicho programa será descrito más adelante.

     Los programas que formatean los discos a mayor capacidad de la normal suelen limitarse a reducir el GAP 3 al formatear, colocando gracias a ello más sectores en las pistas. Sin embargo, la utilidad propuesta aquí rompe con el tamaño estándar de 512 bytes: al colocar sectores de mayor tamaño, existen menos sectores y también menos GAP de separación. El inconveniente de este método es que difícilmente sectores de 1024, 2048 ó más bytes pueden encajar aprovechando óptimamente la capacidad de la pista. Por ello se han adoptado dos soluciones diferentes que han originado 8 nuevos formatos de disco (2 por cada tipo de medio magnético):

        +---------------------+
        | Parámetros /X e /Y  |
        | de FDFORMAT para un |
        | formateo correcto.  |
        +---------------------+
        |    /X        /Y     |
+-------+----------+----------+
| 5¼-DD |     1    |    3     |
| 5¼-HD |     2    |    3     |
| 3½-DD |     1    |    2     |
| 3½-HD |     2    |    3     |
+-------+----------+----------+

     A lo largo de este apartado se hará alguna referencia al popular programa de formateo FDFORMAT creado por Christoph H. Hochstätter; esta utilidad permite formatear disquetes normales desplazando los sectores de manera óptima (opciones /X e /Y) y también añadir más sectores (estrechando el GAP 3). Para superar las limitaciones de flexibilidad de la BIOS es preciso tener residente un pequeño programa de sólo 128 bytes de cara a soportar los formatos extendidos. Este programa, bastante superior al FORMAT en todos los aspectos, con el que además es compatible, está muy extendido en las principales BBS (su código fuente en Turbo Pascal viene incluido) y aborda desde otro punto de vista la ampliación de la capacidad normal de los disquetes, respetando los sectores de 512 bytes. No hay que olvidar que este programa permite crear, además de algunos formatos extendidos, disquetes totalmente estándar de 360K, 1.2M, 720K y 1.44M que, por supuesto, no necesitan soporte residente y son mucho más rápidos que los creados por el FORMAT del DOS. Mientras el FORMAT del sistema operativo no corrija la numeración incorrecta de sectores, que lleva practicando desde 1981, y a la espera de que David Astruga saque la próxima versión de su programa de copia y formateo (a finales del 94 o comienzos del 95); por el momento, FDFORMAT y sus parámetros /X e /Y constituyen la única solución para los usuarios más entendidos (aquellos que usan 4DOS en vez de COMMAND.COM, QEMM en lugar de EMM386, etc): emplear el FORMAT actual no es de conservadores sino de no informados. 2M (abreviatura de 2 megas, aunque no se alcanza esa capacidad por disco) es un programa residente que da soporte a los nuevos formatos de disco. Una vez instalado 2M en memoria, los nuevos disquetes serán reconocidos sin problemas: se podrá hacer DIR, COPY, CHKDSK,... e incluso DISKCOPY hacia un disco destino ya formateado. El código residente de 2M funciona también bajo WINDOWS 3.X;  sin embargo, en OS/2 2.1 hay problemas, aunque se pueden arreglar, como veremos luego, usando el DOS de Microsoft (y no el que viene con el propio OS/2) desde un disquete o, mejor aún, creando una imagen en disco duro de ese disquete. De esta última manera, el usuario ni siquiera nota al diferencia entre estas ventanas de DOS y las normales. Tal vez alguien escriba algún día el driver oportuno para facilitar la operación en este sistema... de momento, 2M está diseñado sólo para los sistemas más extendidos. En WINDOWS NT, donde no ha sido probado, probablemente existirán problemas y limitaciones mayores de las que se producen bajo OS/2. Al momento de escribirse estas líneas, el autor de 2M tiene constancia de que hay intentos de portarlo al sistema operativo Linux por parte de Alain Knaff y David Niemi, si bien desconoce el grado de avance en esta materia.

+------------------------------------------------------------------------+
|                                                                        |
|  [1867/1867] B:\>dir                                                   |
|                                                                        |
|   Volume in drive B is unlabeled      Serial number is 2FE6:7632       |
|  File not found "B:\*.*"                                               |
|             0 bytes in 0 file(s)                                       |
|     1.912.320 bytes free                                               |
|                                                                        |
|                                                                        |
|  [1867/1867] B:\>chkdsk                                                |
|  Número de serie de volumen es 2FE6-7632                               |
|                                                                        |
|     1912320 bytes de espacio total en disco                            |
|     1912320 bytes disponibles en disco                                 |
|                                                                        |
|         512 bytes en cada unidad de asignación                         |
|        3735 total de unidades de asignación en el disco                |
|        3735 unidades de asignación disponibles en disco                |
|                                                                        |
|      655360 bytes de memoria total                                     |
|      649760 bytes libres                                               |
|                                                                        |
|                                                                        |
|  [1867/1867] B:\>testdisk                                              |
|  TD-Test Disco, Edición Estandar 4.50, (C) Copr 1984-88, Peter Norton  |
|  Traducción Castellano, Copyright (C) 1989 ANAYA Multimedia, S.A.      |
|                                                                        |
|  Verificar DISCO, ARCHIVO, o AMBOS                                     |
|  Pulse D, F, o A ... D                                                 |
|                                                                        |
|  Puede pulsar BREAK (Ctrl-C) durante la                                |
|  verificación para interrumpir Test Disco                              |
|                                                                        |
|  Test leyendo el disco B:, zonas del sistema y de datos                |
|    La zona del sistema consta de boot, FAT, y directorio               |
|      Zona del sistema sin errores                                      |
|                                                                        |
|    La zona de datos consta de clusters numerados 2 - 3.736             |
|      Zona de datos sin errores                                         |
|                                                                        |
|                                                                        |
|  [1867/1867] B:\>_                                                     |
+------------------------------------------------------------------------+
            EJEMPLO DE ACCESO A DISQUETE 2M DE 1.44 FORMATEADO A CASI 1.90

     2M añade un nuevo servicio a la INT 13h para poder formatear los nuevos disquetes. No es probable que gracias a ello la próxima versión de PC-TOOLS soporte los nuevos formatos, pero añadir rutinas de formateo apenas alargaba el código residente (sólo 0.75 Kb más hasta alcanzar los 5 Kb) y se trataba de la solución más elegante. Para formatear los nuevos disquetes se ha creado un programa en C de alto nivel, que sencillamente invoca la INT 13h sin verse obligado a realizar ni un solo acceso directo al hardware, pese a que el código residente de 2M accede siempre a disco a través del controlador de disquetes,  sin  una  sola llamada al DOS/BIOS en ningún momento.

+-----------------------------+----------------------------------+--------+
|         Ensamblador         |            Comentario            | Offset |
+-----------------------------+----------------------------------+--------+
|       JMP   SHORT BootP     ; 2 bytes                                0  |
|       NOP                   ; 1 byte                                 2  |
|       DB    "2M-STV08"      ; ID sistema                             3  |
|       DW    512             ; bytes/sector                          11  |
|       DB    1               ; sectores por cluster                  13  |
|       DW    1               ; sectores reservados al principio      14  |
|       DB    2               ; nº copias de la FAT                   16  |
|       DW    224             ; entradas al directorio raíz           17  |
|       DW    3608            ; nº total de sectores del disco        19  |
|       DB    0F0h            ; byte descriptor de medio              21  |
|       DW    11              ; sectores ocupados por la FAT          22  |
|       DW    22              ; sectores por pista                    24  |
|       DW    2               ; nº de cabezales                       26  |
|       DD    0               ; sectores especiales reservados        28  |
|       DD    0               ; nº sectores (unidad 32 bit)           32  |
|       DB    0               ; unidad física                         36  |
|       DB    0               ; reservado                             37  |
|       DB    29h             ; disco con número de serie             38  |
|       DD    8BC1AD20h       ; número de serie provisional           39  |
|       DB    "NO NAME    "   ; título del disco                      43  |
|       DB    "FAT12   "      ; tipo de FAT                           54  |
|       DB    Flags           ; bit 0 = 1 si FechaF/HoraF definido    62  |
|       DB    ?               ; checksum de la información vital      63  |
|       DB    7               ; versión formato (>=7 si BOOT virtual) 64  |
|       DB    0               ; a 1 si escribir al formatear          65  |
|       DB    0               ; velocidad transferencia pista 0       66  |
|       DB    0               ; velocidad transf. demás pistas        67  |
|       DW    BootP           ; offset al programa de arranque        68  |
|       DW    Infp0           ; T1: información para pista 0          70  |
|       DW    InfpX           ; T2: información demás pistas          72  |
|       DW    InfTm           ; T3: tabla tamaños demás pistas        74  |
|       DW    FechaF          ; Fecha de formateo (2M 3.0+)           76  |
|       DW    HoraF           ; Hora de formateo (2M 3.0+)            78  |
| Infp0 DB    19, 70          ; nº sectores / GAP de formateo             |
|       DB    1,2,3,4,5,6,7,8 ; sectores ordenados (20..22 no existen)    |
|       DB    9,10,11,12,13,14                                            |
|       DB    15,16,17,18,19                                              |
| InfpX DB    11, 40          ; nº sectores / GAP de formateo             |
|       DB    3               ; tamaño                                    |
|       DB    1, 2            ; desplazamiento numeración                 |
| InfTm DB    3,3,3,3,3,3     ; tamaño sector 1, 2, 3,...                 |
|       DB    3,3,3,3,3                                                   |
| BootP ...                   ; programa del sector de arranque           |
+-------------------------------------------------------------------------+
                         SECTOR DE ARRANQUE DE UN DISQUETE 2M DE 3½ A 1.80M

     La capacidad obtenida por 2M supera la conseguida por los programas comerciales de backup en los formatos especiales para almacenar sólo datos. Con la ayuda de un compresor de datos de dominio público líder (PKZIP, ARJ, etc) también superior en rendimiento a los programas de backup, se puede conseguir el método de backups que, indiscutiblemente, más aprovecha los disquetes, con una aplastante diferencia -y además el más barato-. Sin embargo, el usuario debería tener cuidado con el tipo de datos que almacena en estos discos, ya que no son tan portables como los estándar y sería problemático migrarlos después a otros entornos.

     Existen versiones de 2M tanto para sistemas AT como para PC/XT, con el único requisito de que la controladora y las unidades sean de alta densidad.

12.6.7.1 - FORMATO DE LA PRIMERA PISTA.

     La primera pista (cilindro y cabezal 0) de los nuevos disquetes tiene el formato normal de sectores de 512 bytes, conteniéndolos en cantidad también más o menos normal. Uno de los motivos es permitir que la FAT, zona del disco en la que a menudo cambia un sólo sector (y no varios consecutivos) tenga un acceso más ágil. En algunos formatos de disco, parte del directorio raíz también cabe en esta pista; en cualquier caso, esto no es demasiado importante porque sólo se accede al directorio raíz una vez por cada fichero.

     Debido al empleo en la primera pista de sectores físicos de 512 bytes, no se pueden emular todos los sectores virtuales. En 3½-HD por ejemplo, los nuevos formatos de disco contarán aparentemente con 22-23 sectores por pista. Realmente serán muchos menos y de más de 512 bytes, pero se engañará al DOS para hacerle creer que son la cantidad citada de sectores de 512 bytes, de cara a mantener la compatibilidad. En cualquier caso, esta cifra es muy superior a los 18 sectores habituales en este tipo de disco. Como la primera pista contiene sectores reales de 512 bytes, no se pueden meter tantos (no caben más de 21 y eso juntando excesivamente los sectores, como hace FDFORMAT en el formato 1.72M).

     Para arreglar este problema, el código residente de 2M se extralimita en sus funciones y, suponiendo que los discos se emplean bajo DOS, ignora las escrituras sobre la segunda copia de la FAT (que estaría sobre alguno de los sectores que no existen en la primera pista) devolviendo la primera copia de la FAT a quien quiera leer la segunda. Así se consigue además una pequeña velocidad extra, ya que la escritura sobre la segunda copia de la FAT que realiza el DOS al crear ficheros resulta ignorada. Realmente, es un poco innecesaria la presencia de 2 FAT en un disquete, máxime teniendo en cuenta que su adyacencia física propicia que en caso de daño se estropeen las dos (¿cuántas veces el lector ha tenido que echar mano de la segunda copia de la FAT para recuperar sus datos?). El MS-DOS, incluso en la versión 6.0 no respeta sus propias especificaciones y asume que los disquetes tienen 2 copias de la FAT: aunque se indique sólo una en el sector de arranque, hará caso omiso. Esta es, por un lado, una buena manera de darle el corte de mangas; por otro, un medio ideal para simular más sectores en la primera pista física.

+-----------------------------+----------------------------------+--------+
|         Ensamblador         |            Comentario            | Offset |
+-----------------------------+----------------------------------+--------+
|       JMP   SHORT BootP     ; 2 bytes                                0  |
|       NOP                   ; 1 byte                                 2  |
|       DB    "2M-STV04"      ; ID sistema                             3  |
|       DW    512             ; bytes/sector                          11  |
|       DB    1               ; sectores por cluster                  13  |
|       DW    1               ; sectores reservados al principio      14  |
|       DB    2               ; nº copias de la FAT                   16  |
|       DW    224             ; entradas al directorio raíz           17  |
|       DW    3772            ; nº total de sectores del disco        19  |
|       DB    0F0h            ; byte descriptor de medio              21  |
|       DW    11              ; sectores ocupados por la FAT          22  |
|       DW    23              ; sectores por pista                    24  |
|       DW    2               ; nº de cabezales                       26  |
|       DD    0               ; sectores especiales reservados        28  |
|       DD    0               ; nº sectores (unidad 32 bit)           32  |
|       DB    0               ; unidad física                         36  |
|       DB    0               ; reservado                             37  |
|       DB    29h             ; disco con número de serie             38  |
|       DD    4B368A0Eh       ; número de serie (aleatorio)           39  |
|       DB    "NO NAME    "   ; título del disco                      43  |
|       DB    "FAT12   "      ; tipo de FAT                           54  |
|       DB    Flags           ; bit 0 = 1 si FechaF/HoraF definido    62  |
|       DB    ?               ; checksum de la información vital      63  |
|       DB    7               ; versión formato (>=7 si BOOT virtual) 64  |
|       DB    1               ; a 1 si escribir al formatear          65  |
|       DB    0               ; velocidad transferencia pista 0       66  |
|       DB    0               ; velocidad transf. demás pistas        67  |
|       DW    BootP           ; offset al programa de arranque        68  |
|       DW    Infp0           ; T1: información para pista 0          70  |
|       DW    InfpX           ; T2: información demás pistas          72  |
|       DW    InfTm           ; T3: tabla tamaños demás pistas        74  |
|       DW    FechaF          ; Fecha de formateo (2M 3.0+)           76  |
|       DW    HoraF           ; Hora de formateo (2M 3.0+)            78  |
| Infp0 DB    19, 70          ; nº sectores / GAP de formateo             |
|       DB    1,2,3,4,5,6,7,8 ; sectores ordenados (20..23 no existen)    |
|       DB    9,10,11,12,13,14                                            |
|       DB    15,16,17,18,19                                              |
| InfpX DB    64, 3           ; nº sectores / GAP de formateo             |
|       DB    7               ; nº sectores a renumerar                   |
|       DB    128+1,  4, 4    ; tabla de renumeración formateo:           |
|       DB    128+12, 1, 4    ; nº sector, nuevo número, tamaño           |
|       DB    128+23, 5, 4                                                |
|       DB    128+34, 2, 4                                                |
|       DB    128+45, 6, 3                                                |
|       DB    128+51, 3, 4                                                |
|       DB    128+62, 7, 2                                                |
| InfTm DB    4,4,4,4,4,3,2   ; tamaño sector 1, 2, 3,...                 |
| BootP:...                   ; programa del sector de arranque           |
+-------------------------------------------------------------------------+
                         SECTOR DE ARRANQUE DE UN DISQUETE 2M DE 3½ A 1.88M

     El sector de arranque de los nuevos disquetes es en principio similar al de cualquier otro disco, pero contiene más información adicional para describir el formato físico de disco que se trate y así poder gestionarlo luego. De esta manera, se sistematiza el soporte de los nuevos formatos y se simplifica el programa residente. Detrás de los primeros 62 bytes, donde va la información colocada por el FORMAT normal del DOS (incluyendo las últimas modas, como campos para etiqueta de disco, número de serie, etc.) existen unos campos con información adicional, que describiremos más adelante. Detras de este área está el programa de arranque del disquete, que en sus primeras versiones se limitaba a imprimir en pantalla un mensaje diciendo que el disco no es de arranque; actualmente arranca desde el disco duro si éste existe y, desde 2M 2.0, carga el código SuperBOOT almacenado en el disco si es de alta densidad. Los discos 2M de alta densidad utilizan 5 sectores libres de la segunda copia de la FAT (ubicados en la primera pista) para almacenar gran parte del código residente de 2M (todo, excepto las rutinas de formateo). De esta manera, desde 2M 2.0 es posible botar de un disco 2M de alta densidad, que puede crearse con un SYS ordinario. De hecho, el primer sector de la segunda copia de la FAT emula al auténtico sector de arranque, y los 5 restantes almacenan el código residente de 2M. Así, cuando 2M está instalado, el comando SYS y cualquier aplicación que acceda al sector de arranque estará accediendo realmente a un falso sector de arranque que está físicamente colocado en la FAT2. Y podrá modificarlo sin riesgo alguno para 2M, ya que el auténtico sector de arranque permanece inmutable; las versiones anteriores de 2M necesitaban proteger este sector restringiendo de alguna manera su acceso (para evitar que un simple SYS lo modificara y borrara la información vital que contiene). La denominación SuperBOOT para el código de 2M almacenado en la primera pista de los discos se debe exclusivamente a cuestiones de marketing. Debido a que se necesita un tamaño mínimo de FAT, modificar el tamaño de cluster en el sector de arranque no es conveniente, aunque está permitido y puede generar discos que no funcionen. Sin embargo, la utilidad estándar de formateo no deja cambiar el tamaño de cluster (por otra parte de sólo 512 bytes) y no hay muchos programas conocidos que alteren estos parámetros de los disquetes ya formateados.

     Cuando el sistema arranca de un disco 2M de alta densidad, el código SuperBOOT rebaja la memoria libre en 5 Kbytes (normalmente, de 640K a 635K) ubicándose al final de la memoria convencional y se instala en la INT 13h. Después, se carga el sector de arranque vía INT 13h (que en adelante será el falso sector de arranque emulado, al que pudo acceder el SYS) y se ejecuta, procediéndose al arranque normal del sistema, ya que la nueva BIOS soporta discos 2M... este sector de arranque ubicado en la FAT2 es denominado sector de arranque virtual en la documentación de 2M. Como puede observar el lector, dejar la primera pista con sectores de 512 bytes y emular la segunda copia de la FAT sobre la primera fue una idea primitiva que luego ha permitido muchas aplicaciones interesantes.

     Naturalmente, está previsto un mecanismo para poder acceder a los sectores físicos sin emulaciones: esto es útil además para permitir al programa de formateo grabar el código SuperBOOT y acceder al sector de arranque físico, ya que los programas normales no tienen motivos especiales para necesitar un acceso a dichas áreas. Cuando 2M está instalado, cualquier acceso al cabezal 128 ó 129 en lugar del 0 ó el 1 permite acceder al disco sin realizar ningún tipo de emulación; si bien esto sólo funciona con discos 2M (con un disco estándar en la unidad, aunque 2M esté instalado, el acceso a estos cabezales devuelve un error).

     En adelante nos referiremos al sector de arranque físico, no al virtual (que puede ser distinto si el disco es de sistema o ha sido alterado por alguna utilidad). El primer campo propio de 2M en el sector de arranque es una variable con flags, empleada sólo desde 2M 3.0 para indicar si se almacena la fecha y hora de formateo en el sector de arranque (bit 0 = 1 en caso afirmativo). Detrás hay un checksum o suma de comprobación de la zona vital del sector de arranque. El algoritmo empleado ha variado en las sucesivas versiones del programa. Desde la versión 6 del formateador (byte ubicado justo después del checksum) la zona total afectada por el checksum va desde el offset 64 hasta justo antes del programa de arranque del disco. Las versiones anteriores de 2M realizaban un checksum distinto, por lo que los discos formateados por ellas no están sujetos a la comprobación de checksum para evitar problemas. La suma total de este área (en número de 8 bits) debe dar un resultado 0. Por tanto, se permite modificar el programa de arranque e incluso los campos del principio. Cualquier otro cambio no permitido hará que 2M falle en la comprobación del checksum la primera vez que el disco es introducido en la unidad; en este caso INT 13h devuelve un Seek Error poco habitual para señalizar la circunstancia. Sin embargo, un cambio en el campo ID (bytes 3 al 10) podría acarrear que 2M no reconociera el disco como suyo. Quizá el lector opine que hubiera sido mejor ser más tolerantes, pero yo opino que no: si el sector de arranque está corrompido, el código residente de 2M, que no valida nada de dicho sector, podría estrellarse si se fía de la información del mismo. Así nadie podrá decir: «se me cuelga al hacer DIR A:», como mucho: «me dice Seek Error y no me deja acceder al disco». En realidad, es difícil que se produzcan estos errores porque nadie que intente alterar el sector de arranque físico lo podrá conseguir con 2M en memoria, sin saber como hacerlo o sin acceder directamente a la controladora.

                                                   +---------------------------------------+
                                                   |   GAPs y /X e /Y probados en 2MF /F   |
                                                   +---------+---------+---------+---------+
                                                   |  5¼-DD  |  5¼-HD  |  3½-DD  |  3½-HD  |
+--------------------------------------------------+---------+---------+---------+---------+
| GAP mínimo de lectura soportado en las pruebas   |     1   |     2   |     1   |     2   |
| GAP mínimo de escritura soportado en las pruebas |    13   |    26   |    20   |    28   |
| GAP máximo de escritura soportado en las pruebas |   197   |    76   |   187   |    49   |
| GAP 3 de formateo adoptado finalmente            |   100   |    50   |   100   |    40   |
| Valor óptimo obtenido experimentalmente para /X  |     1   |     1   |     1   |     1   |
| Valor óptimo obtenido experimentalmente para /Y  |     1   |     2   |     1   |     2   |
+--------------------------------------------------+---------+---------+---------+---------+
2MF ES EL FORMATEADOR PARA 2M. CON /F SE CREAN DISCOS NORMALES Y /M INDICA MÁXIMA CAPACIDAD.

     Tras el checksum hay un byte que indica la versión del formateador, de cara a permitir que futuras versiones de 2M sepan con qué formato de disco se enfrentan para respetar los viejos formatos (en caso de que surjan otros nuevos). El siguiente byte indica si es necesaria una escritura tras el formateo: en los formatos de más capacidad, trasformatear la pista hay que escribirla para evitar que una lectura posterior produzca errores de CRC, como luego veremos y explicaremos. En los formatos normales este byte estará a 0, y a 1 en los de más capacidad.

     Los siguientes 2 bytes indican la velocidad de transferencia a emplear en la primera pista (cilindro y cabezal 0) y en las demás; el dato no está, por supuesto, en Kbit/seg sino que se trata del valor que hay que enviar al registro de salida digital. En los disquetes de 3½-DD se utilizará la velocidad de 250 Kbit/seg en la primera pista y 300 Kbit/seg en las demás. El motivo es que las primeras versiones de 2M delegaban parte del trabajo de reconocer la densidad de disco a la BIOS, la cual sólo soporta 250 Kbit/seg en estas unidades. Actualmente no sería necesario, ya que 2M detecta la densidad de los discos (y de hecho, sustituye a la BIOS original en esta tarea), pero se ha mantenido por compatibilidad con los primeros formatos de disco de 2M. Tras estos campos hay unos punteros a diversas áreas interesantes: el primero apunta al programa de arranque y será empleado por dicho programa para conocer con comodidad su propia ubicación; después hay un puntero a una tabla con información sobre la estructura de la primera pista del disco, otro puntero apunta a una tabla con información de las demás pistas y, finalmente, un último puntero referencia una tabla de tamaños de los sectores de las pistas (excepto la primera). Los últimos campos sólo se emplean desde 2M 3.0 y almacenan la fecha y hora de formateo.

     La primera tabla contiene un byte que indica el número real de sectores de la primera pista, seguido de otro byte con el valor de GAP 3 empleado al formatear. Después vienen los números de sectores, uno tras otro, lo que permite elegir líbremente el interleave. Las últimas versiones de 2M acceden de manera eficiente a la primera pista (y a todas las demás) soportando perfectamente un interleave 1:1, si bien los primeros disquetes 2M fueron formateados con un factor 1:2. En los formatos de 1.80/1.88M la FAT ocupa 11 sectores, y otro el sector de arranque físico. Los sectores que van del 1 al 12 están, por lo tanto, necesariamente ocupados; pero del 13 al 19 hay sitio para 7 sectores que pueden contener el BOOT virtual (1 sector) y el código SuperBOOT (5 sectores). El sector restante se debe a que en discos de 1.88M con 84 pistas la FAT1 ocuparía un sector más.

        +--------------------------------+---------------------------------------------------------------------------------------+
        | Capacidad bruta real antes de  |                Bytes netos obtenidos por los principales formateadores                |
        | formatear (con 82 pistas y en  +---------------------+---------------------+---------------------+---------------------+
        | controladora de alta densidad) | FORMAT (40/80p) (*) | FDFORMAT (82p) (**) |   2MF 3.0 /F (82p)  |   2MF 3.0 /M (82p)  |
+-------+--------------------------------+---------------------+---------------------+---------------------+---------------------+
| 5¼-DD |   1.025.000 bytes  (0,98 Mb)   |    368.640  (360K)  |    839.680  (820K)  |    839.680  (820K)  |    923.648  (902K)  |
| 5¼-HD |   1.708.224 bytes  (1,63 Mb)   |  1.228.800 (1200K)  |  1.511.424 (1476K)  |  1.511.424 (1476K)  |  1.595.392 (1558K)  |
| 3½-DD |   1.230.000 bytes  (1,17 Mb)   |    737.280  (720K)  |    839.680  (820K)  |  1.007.616  (984K)  |  1.091.584 (1066K)  |
| 3½-HD |   2.050.000 bytes  (1,96 Mb)   |  1.474.560 (1440K)  |  1.763.328 (1722K)  |  1.847.296 (1804K)  |  1.931.264 (1886K)  |
+-------+--------------------------------+---------------------+---------------------+---------------------+---------------------+
                                                             (*) También FDFORMAT cuando se emplean los formatos estándar del DOS.
                                                                     (**) Formatos de máxima capacidad soportados (820-1.48-1.72).

     La segunda tabla contiene información de las demás pistas del disco. El contenido y el formato de esta tabla varía según el tipo de disco: los formatos normales (como el caso de 1.80M) poseen 5 bytes: el primero indica el número de sectores de la pista, el siguiente el GAP 3 al formatear, otro byte indica el tamaño de sector empleado  (siempre 3, esto es, 1024 bytes)  y los dos últimos bytes son equivalentes a los parámetros /X e /Y de FDFORMAT para desplazar de manera óptima la numeración de los sectores en las pistas consecutivas. Estos valores de /X e /Y son sensiblemente menores que los de FDFORMAT, pero no hay que olvidar que aquí los sectores son dos veces más grandes. En los formatos de disco de máxima capacidad (como en 1.88M) esta tabla cambia radicalmente de estructura: el primer byte sigue siendo el número de sectores, pero ahora son sectores de 128 bytes. Esto se debe a que en estos formatos, las pistas son preformateadas (en una primera pasada) con sectores de 128 bytes. El siguiente byte es el GAP 3, que como se puede observar es muy pequeño (de 3 a 5 bytes). Finalmente, viene el número de sectores a renumerar. La razón es que, durante el formateo, se asignan números a partir de 129 a la mayoría de los sectores; sin embargo, algunos de ellos no se llevan el que les correspondería sino que siguen otra numeración más baja a partir de 1. En estos sectores, además, al ser enviada su información al FDC durante el formateo, se indicará un tamaño distinto de 128 (512, 1024 ó 2048). Así, por ejemplo, en 1.88M la pista queda formateada con nada menos que 64 sectores de 128 bytes numerados desde 129, habiendo sin embargo algunos de ellos con números más bajos (1, 2,..., 7) y definidos con mayor tamaño. Al ser escritos dichos sectores (segunda fase del formateo) se machacarán los sectores de 128 bytes que les siguen y quedarán sólo ellos en la pista. Esto permite colocar sectores de distinto tamaño en la pista. El GAP 3 definitivo será mayor (13 bytes en el peor de los casos). Ahora comprenderá el lector por qué había que escribir la pista, después del formateo, en estos formatos de disco... Por último, señalar que en esta tabla se elige un factor de interleave adecuado, que si se echa un vistazo resulta ser de 1:2, ya que los sectores están demasiado próximos para numerarlos consecutivamente (por razones de velocidad, si bien al ser accedidos uno a uno la controladora no tendría problemas para encontrarlos). En el caso del formato 1.88M, por ej., quedan numerados: 4,1,5,2,6,3,7.

     La última tabla es la única que realmente emplea 2M para acceder a todas las pistas, con excepción de la primera. Se trata de una lista ordenada de los tamaños de los sectores. En los formatos de disco normales es una lista de treses, ya que todos los sectores son iguales y de 1024 bytes. En los formatos de máxima capacidad, como 1.88M, se puede comprobar que la lista es más variada. Las otras dos tablas vistas con anterioridad sólo son empleadas durante el formateo del disco.

12.6.7.2 - PUNTUALIZACIONES SOBRE EL FORMATO DE MAXIMA CAPACIDAD.

     El formateo de disquetes 2M se realiza con un programa que veremos más adelante, 2MF.EXE, que permite elegir entre formatos normales (2MF sin parámetros o con la opción /F) y formatos de máxima capacidad (2MF /M). Como se vio en la descripción del sector de arranque, el formato de máxima capacidad logra introducir sectores de distinto tamaño en la misma pista. Seguramente la descripción dada en el apartado anterior no ha quedado muy clara, por lo que ahora puntualizaremos un poco más.

     Uno de los principales objetivos al realizar 2M fue conseguir un nivel de compatibilidad lo suficientemente alto, incluso en los formatos menos seguros como el que se describirá a continuación, al menos en comparación con los ya estudiados de sectores de 1 Kb. Hay disqueteras de 1.44M que soportan el formateo de 3 sectores de 4096 bytes en una pista, lo que permitiría obtener 1968K (en 82 cilindros, soportados por prácticamente todas las unidades). Sin embargo, hay muchos ordenadores en que esto no es posible, por tanto esta solución fue descartada. En los casos en que es posible, lo es además a costa de rebasar con creces los mínimos niveles de seguridad (machacando no sólo el GAP ubicado al final de la pista, sino también el del principio e incluso el IAM; resulta increíble que algunas controladoras de disquete continúen reconociendo los sectores). Además, se trataría de una solución exclusiva para disquetes de 1.44M.

     El truco explicado con anterioridad consiste en formatear los discos con sectores muy pequeños de 128 bytes, pero definiéndoles con tamaños de 512, 1024 y 2048 bytes al enviar la información de cada sector al controlador, de cara a agruparles posteriormente para obtener sectores de mayor tamaño. Echando cuentas, con un GAP 3 provisional de sólo 3 bytes (podríamos denominarlo GAP virtual) cada sector ocupa 128+62+3 = 193 bytes. Agrupando 11 de estos sectores se obtienen 193*11=2123 bytes, suficientes para contener un sector de 2048 bytes, los 60 bytes añadidos al principio del primer sector de 128 bytes por el FDC, los 2 bytes añadidos al final del último sector por el FDC y otros 13 bytes de GAP 3. Agrupando 6 sectores se obtienen 1158 bytes, suficientes para contener un sector de 1024 bytes con un GAP 3 de 72 bytes. Finalmente, agrupando 3 se consiguen 579 bytes, en los que cabe un último sector de 512 bytes con un GAP 3 de 5 bytes. Así, en un disquete estándar de 1.44M, con 12500 bytes por pista, donde caben bastante holgadamente 64 sectores de 128 bytes de las características mencionadas, se pueden colocar 5 grupos de 11, 1 de 6 y otro de 3. En total: 11,5 Kb en cada pista (1886 en todo el disco, a 82 cilindros). Una vez formateada la pista, es conveniente escribir todos los sectores (la primera lectura daría error de CRC en caso contrario), de paso se asegura de esta manera, en una posterior lectura, que la escritura no ha provocado que ningún sector pise a otro, asegurando la fiabilidad del método. Una vez que el disco ha sido formateado, la verificación realizada durante el formateo garantiza que es seguro; la separación o GAP 3 medio menor es de 13 bytes y puede considerarse bastante razonable (el sector de 512 bytes con un GAP 3 de sólo 5 es colocado siempre al final de la pista); en los disquetes de doble densidad es además superior, al emplearse un GAP 3 virtual en la primera fase de 4 ó 5 bytes en vez de 3.

     El formateo es relativamente lento, ya que requiere tres fases: formateo, escritura y lectura para verificar; cada una de ellas, dada la proximidad de los sectores, requiere de dos vueltas del disco (los sectores estarán numerados alternamente con un razonable interleave 1:2); en total, 6 vueltas en un disco de 1.44M por cada pista, lo que equivale a 1,2 segundos por pista y 3:17 minutos en el conjunto del disquete (2 caras y 82 cilindros). Este es el precio que hay que pagar para obtener 1.912.320 bytes libres netos (los que aparecen al hacer un DIR) frente a los 1.457.664 conseguidos por el FORMAT del DOS.

     Un último detalle a tener en cuenta es que, en este tipo de formato, al escribir el cabezal 1 del cilindro 0, el código de 2M se saltará el acceso al primer sector de la pista (al estar la FAT2 en él, por regla general, y debido a las emulaciones). Por tanto, en este caso, es necesario escribir en el cabezal 129 para asegurar que realmente se escribe la pista y el disco queda correctamente inicializado. Por comodidad, se puede escribir en el cabezal 128/129 de todas las pistas (salvo la primera, que no tiene realmente tantos sectores como las demás y que además tampoco es necesario escribir tras el formateo).

12.6.7.3 - DESCRIPCION DE FUNCIONAMIENTO DEL SOPORTE RESIDENTE (2M).

     2M es un programa residente ordinario que desvía la INT 13h/40h. En las máquinas AT con disco duro de tipo IDE (los más extendidos actualmente) o con una controladora de disco duro ordinaria de AT, la BIOS desvía a INT 40h los servicios de disquete, siendo invocada esta interrupción desde la INT 13h para atender las funciones de disquete. Sin embargo, si el ordenador no tiene disco duro o incorpora una controladora de disco duro de XT, es la INT 13h quien podría controlar los disquetes. La versión 1.0 de 2M desviaba la INT 40h en lugar de la INT 13h, por el motivo que ahora analizaremos (ayuda en la cuestión del DMA); sin embargo, ésto hacia que el programa no funcionara en algunas máquinas AT sin disco duro o con controladora de XT. Por ello, en la versión 1.1 se volvió a trabajar con INT 13h. Pero desde 2M 2.0+, aunque ahora más por razones de seguridad que de comodidad, se utiliza una técnica mixta: si el ordenador emplea la INT 40h, 2M se instala desde esta interrupción; en caso contrario, lo hace desde INT 13h (actuándo desde INT 40h el programa toma el control de los discos antes que otros TSR instalados después). Y volvamos sobre la cuestión del DMA, que motivó el uso de INT 40h en 2M 1.0. Como el lector recordará, a la hora de transferir con la disquetera hay que tener cuidado con las fronteras de DMA. Sin embargo, resultaría muy engorroso tener que tener esto en cuenta en los programas de alto nivel. El propio DOS considera que es un auténtico fastidio tener que comprobar esto cada vez que se accede al disco. Por ello, cuando el sistema operativo se carga en el ordenador desvía la INT 13h y la modifica para arreglar de un plumazo los problemas con el DMA: a partir de ese momento, la INT 13h es realmente controlada por el DOS, aunque se trate de una interrupción BIOS. Las nuevas rutinas de la INT 13h colocadas por el DOS se limitan a llamar a la vieja INT 13h (nadie ha hablado aún de INT 40h) y, cuando se produce un error de frontera de DMA, la operación de disco que lo había provocado es segmentada probablemente en tres fases: los sectores que estaban antes de la frontera, los que quedan por detrás y el que cae justo en medio; este sector es probablemente transferido a través de un buffer intermedio del sistema.

        +-----------------------------------------------------------------------------------+
        |             Porcentaje de disco aprovechado (perdido) tras el formateo            |
        +--------------------+--------------------+--------------------+--------------------+
        |       FORMAT       |    FDFORMAT 1.8    |    2MF 3.0  /F     |     2MF 3.0  /M    |
+-------+--------------------+--------------------+--------------------+--------------------+
| 5¼-DD |  35,96%  (64,04%)  |  81,92%  (18,08%)  |  81,92%  (18,08%)  |  90,11%  ( 9,89%)  |
| 5¼-HD |  71,93%  (28,07%)  |  88,48%  (11,52%)  |  88,48%  (11,52%)  |  93,39%  ( 6,61%)  |
| 3½-DD |  59,94%  (40,06%)  |  68,27%  (31,73%)  |  81,92%  (18,08%)  |  88,75%  (11,25%)  |
| 3½-HD |  71,93%  (28,07%)  |  86,02%  (13,98%)  |  90,11%  ( 9,89%)  |  94,21%  ( 5,79%)  |
+-------+--------------------+--------------------+--------------------+--------------------+
| Media |  59,94%  (40,06%)  |  81,17%  (18,83%)  |  85,60%  (14,40%)  |  91,62%  ( 8,38%)  |
+-------+--------------------+--------------------+--------------------+--------------------+

     Si 2M se instala colgando de INT 13h, al introducir un disquete de tipo 2M (cuyo control evidentemente corre a cargo de 2M) todas las llamadas del DOS a la INT 13h serían llamadas a 2M, que ha sido instalado después de que el DOS arregle la INT 13h. Por tanto, 2M debe en ese caso ocuparse de la engorrosa gestión de errores de DMA, ya que el DOS no espera nunca este tipo de error de una llamada a la INT 13h. En la práctica, 2M a partir de la versión 1.1, en las operaciones que afectan a varios sectores de disco consecutivos, se ve obligado a detectar con antelación el futuro cruce de una frontera de DMA: en caso de que se vaya a producir, el sector problemático es transferido a través del buffer intermedio del programa. La versión 1.0 de 2M desviaba INT 40h en vez de INT 13h y se limitaba a devolver la condición de error cuando se iba a producir, para que el propio DOS en INT 13h llamara de nuevo con más cuidado.

     2M podría haber sido creado como controlador de dispositivo que definiera nuevas letras de unidad para soportar los nuevos disquetes; sin embargo resulta más intuitivo para el usuario continuar empleando las unidades A: y B: habituales. Esto se consigue, como hemos visto, modificando la INT 13h de la BIOS, lo que además permite el funcionamiento de ciertas utilidades de bajo nivel en los nuevos disquetes; realmente, en el mundo del PC no hay casi programas de utilidad a bajo nivel con el disco. Salvo los copiones, la mayoría de los llamados programas de bajo nivel en materia de disquetes se limitan a llamar a la BIOS. La técnica de ampliar la funcionalidad de la INT 13h de la BIOS es, por tanto, la más eficiente.

     El listado que comentaremos es sólo la parte importante del programa. Desde 2M 3.0 ya no hay listados con partes repetidas: un único fichero 2M.ASM produce 2M.COM (sistemas AT) y 2MX.COM (en PC/XT) por medio del ensamblaje condicional. Para ello se apoya en 2MKERNEL.INC, núcleo principal con todo el código de acceso a la controladora para soportar los discos 2M, y también empleado para generar 2M.SYS (versión driver para AT) y 2MFBOOT.BIN (con código SuperBOOT para el formateador). También se utiliza 2MUTIL.INC para englobar ciertas rutinas de utilidad comunes a más programas de la aplicación. Aquí nos limitaremos a comentar 2MKERNEL.INC, ya que lo restante no está relacionado con la controladora de discos.

     2M puede controlar las unidades de disco A: y B: si son de alta densidad (de lo contrario se limita a invocar a la INT 13h original). Por ello, además de un juego de variables globales, hay una estructura que define las variables propias de una unidad que se emplea para crear dos áreas de datos particulares, una para cada disquetera. A lo largo de la mayoría del código residente, el registro SI estará apuntando a esa zona de variables locales de la disquetera que se trate. Al principio del programa está la rutina que controla la interrupción 2Fh, empleada para gestionar la autodetección en memoria del programa residente y permitir su posible futura desinstalación.

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [   19.58]  19.58    10    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [   37.44]  17.86    11    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [   55.31]  17.87     1    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [   73.18]  17.87     2    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [   91.05]  17.87     3    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  108.91]  17.86     4    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  126.79]  17.87     5    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  144.65]  17.86     6    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  162.52]  17.87     7    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  180.39]  17.87     8    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  198.26]  17.87     9    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  217.85]  19.59    10    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  235.71]  17.86    11    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  253.71]  18.00     1    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  271.57]  17.86     2    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  289.44]  17.87     3    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  307.43]  17.99     4    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  325.43]  17.99     5    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  343.42]  17.99     6    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  361.28]  17.87     7    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  379.16]  17.87     8    1024 (  3)      0       1    0x04  0x00  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [   33.95]  33.95     3    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [   45.32]  11.37     7     512 (  2)      0       1    0x04  0x00  0x00     |
|     [   79.14]  33.82     4    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  112.94]  33.80     1    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  146.76]  33.82     5    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  180.58]  33.82     2    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  198.97]  18.39     6    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  232.78]  33.82     3    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  244.16]  11.37     7     512 (  2)      0       1    0x04  0x00  0x00     |
|     [  277.97]  33.81     4    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  311.78]  33.81     1    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  345.60]  33.81     5    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  379.42]  33.82     2    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  397.80]  18.38     6    1024 (  3)      0       1    0x04  0x00  0x00     |
|     [  431.62]  33.82     3    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  443.00]  11.38     7     512 (  2)      0       1    0x04  0x00  0x00     |
|     [  476.95]  33.95     4    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  510.75]  33.81     1    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  544.57]  33.82     5    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  578.40]  33.83     2    2048 (  4)      0       1    0x04  0x00  0x00     |
|     [  596.79]  18.38     6    1024 (  3)      0       1    0x04  0x00  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+
                     LECTURA DE ID's EN 3½-HD (FORMATO NORMAL Y DE MAXIMA CAPACIDAD)

     La rutina que controla la INT 13h ó INT 40h es más importante. Su labor consiste en pasar el control de las funciones 2 (lectura), 3 (escritura), 4 (verificación) y 5 (formateo) a 2M (si el disquete introducido es de este tipo) o a la interrupción original (si el disquete introducido no es de tipo 2M). Existe una variable por cada unidad que indica en todo momento si el disquete introducido es de tipo 2M (control2m_flag=ON) o no. Otro cometido consiste en detectar los cambios de disco, para actualizar dicha variable en consecuencia. Ante el primer cambio de disco detectado se retorna con un error 6 (porque así lo hace la BIOS original).

     En el caso de la función de formateo (no implementada en el código SuperBOOT por falta de espacio), se mira si quien la invoca solicita un formateo normal o si se trata de una petición de formateo de disquete 2M. Esto es debido a que 2M aumenta la funcionalidad de la función 5 original de la BIOS para soportar los nuevos disquetes. En la función de la BIOS, se indica en AL el número de sectores de la pista, en CH la pista, en DH el cabezal, en DL la unidad y en ES:BX se apunta a un buffer con información para formatear. Cuando está 2M residente y se invoca la función 5 con el registro SI=324Dh (SI="2M") y con AL=7Fh, se le indica a 2M que no llame a la función de formateo original de la BIOS y que formatee él la pista en la unidad y cabezal indicados. En este caso AL es ignorado, ya que en ES:BX lo que se le pasa a la BIOS (es decir, a 2M) no es la dirección de tabla alguna sino el sector de arranque del futuro disquete, que contiene toda la información necesaria sobre la estructura del disco para poder clonarlo. No hay que crear tablas ni emplear otras funciones BIOS para seleccionar densidad ni nada por el estilo. Tampoco hay que considerar la complejidad de los formatos 2M (en los que difiere la primera pista de las restantes): de todo se ocupa el código residente del propio 2M. La rutina format_2m invocada desde ges_int13 se encarga del formateo. Primero se llama a la INT 13h original (previa a 2M) para solicitar un formateo en el cabezal 2, inexistente, con objeto de que retorne rápidamente ante el error. Así, se avisa a todos los demás programas residentes de que el disco va a ser formateado: el propio DOS invalida los buffers asociados al viejo disquete; si 2M no tomara esta medida, al hacer DIR sobre el disco recién formateado aparecería aún, falsamente, su contenido previo. A continuación realiza las siguientes tareas: toma nota de los parámetros del futuro disco, pone en marcha el motor, lleva el cabezal a la pista, crea la tabla con información para el formateo, formatea la pista y retorna con el código de error o éxito correspondiente. En los formatos de máxima capacidad, recuérdese que había que escribir la pista tras el formateo, para evitar que la primera lectura diera error y para completar realmente el proceso. Sin embargo, el código residente de 2M no escribe nada tras el formateo. Esto permite en este caso a los programas de copia de disquetes poder ir escribiendo el disco destino a la vez que formatean; lo contrario sería una pérdida de tiempo con una escritura muerta. En el caso de programas que sólo formateen, tendrán además que escribir; esto implica que esos programas deben estar diseñados para formatear disquetes 2M (nadie ha dicho que el FORMAT del DOS pudiera hacerlo por sí solo).

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [   31.72]  31.72     2    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [   63.27]  31.55     3    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  103.25]  39.98     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  134.76]  31.51     5    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  166.35]  31.59     1    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  197.98]  31.63     2    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  229.53]  31.55     3    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  269.51]  39.98     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  301.01]  31.50     5    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  332.61]  31.60     1    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  364.24]  31.63     2    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  395.79]  31.55     3    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  435.77]  39.98     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  467.27]  31.50     5    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  498.86]  31.59     1    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  530.59]  31.72     2    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  562.13]  31.54     3    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  602.12]  39.99     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  633.62]  31.50     5    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  665.22]  31.60     1    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  696.85]  31.63     2    1024 (  3)      0       1    0x05  0x00  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|       Longitud (ms)    Sector    Tamaño    Cilindro Cabeza  ST0   ST1   ST2      |
|    ------------------- ------ ------------ -------- ------ ----- ----- -----     |
|     [   56.44]  56.44     3    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  112.90]  56.46     1    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  143.63]  30.73     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  158.92]  15.29     2     512 (  2)      0       1    0x05  0x00  0x00     |
|     [  165.85]   6.93     0     128 (  0)      0       1    0x05  0x00  0x00     |
|     [  222.30]  56.45     3    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  278.75]  56.45     1    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  309.49]  30.73     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  324.78]  15.29     2     512 (  2)      0       1    0x05  0x00  0x00     |
|     [  331.70]   6.92     0     128 (  0)      0       1    0x05  0x00  0x00     |
|     [  388.16]  56.46     3    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  444.61]  56.45     1    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  475.34]  30.73     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  490.63]  15.29     2     512 (  2)      0       1    0x05  0x00  0x00     |
|     [  497.55]   6.92     0     128 (  0)      0       1    0x05  0x00  0x00     |
|     [  554.01]  56.45     3    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  610.46]  56.45     1    2048 (  4)      0       1    0x05  0x00  0x00     |
|     [  641.19]  30.73     4    1024 (  3)      0       1    0x05  0x00  0x00     |
|     [  656.48]  15.29     2     512 (  2)      0       1    0x05  0x00  0x00     |
|     [  663.41]   6.93     0     128 (  0)      0       1    0x05  0x00  0x00     |
|     [  719.86]  56.45     3    2048 (  4)      0       1    0x05  0x00  0x00     |
|                                                                                  |
|                   Una tecla para leer más ID's [ESC=salir].                      |
+----------------------------------------------------------------------------------+
                     LECTURA DE ID's EN 5¼-DD (FORMATO NORMAL Y DE MAXIMA CAPACIDAD)

     El procedimiento detecta_cambio determina si se ha producido un cambio de disco. En caso de que se haya producido (o la primera vez absoluta que se ejecuta la rutina tras haber instalado 2M en memoria) se intenta leer el sector de arranque del mismo para determinar la densidad del mismo y averiguar si es de tipo 2M. Primero se intenta bajar la línea de cambio de disco: si no fuera posible, es que la unidad está sin disquete introducido. El acceso se intenta tres veces, con todas las densidades posibles (500, 300, 250 Kbit/seg y finalmente 1 Mbps). Si no se pudiera leer el sector de arranque, podría deberse a que es un disco sin formatear, o tratarse de otro medio físico, por lo que se le devuelve el control a la INT 13h original hasta un futuro nuevo cambio de disco. Esto mismo puede suceder si se consigue leer el sector de arranque y la rutina set_info comprueba que el disco es estándar del DOS. Cuando no hay disco en la unidad y se falla al bajar la línea de cambio, se delega el control a la BIOS pero si ésta logra bajarla (¿controladora no compatible?) se le vuelve a robar el control al siguiente acceso. Esta artimaña permitió a versiones antiguas de 2M funcionar en máquinas 486 (cuando no se tomaba la precaución de hacer un retardo al resetear la controladora y ésta quedaba en ocasiones atontada, hasta que la BIOS del sistema la reseteaba bien). En caso de ser un disco 2M se anotan las características del mismo, teniendo en cuenta que lo que acabamos de leer es precisamente su sector de arranque... Como 2M es el encargado de detectar la densidad del disco, es necesario que ajuste las variables de la BIOS indicando dicha densidad, ya que ella será la encargada de controlar los disquetes normales. En realidad, la densidad sólo se ajusta en el primer acceso al disco, existiendo dos variables en el área de datos de la BIOS, en el segmento 40h, que indican la densidad a emplear en cada disquetera: si dichas variables no están correctamente inicializadas, al conmutar de una unidad a otra la BIOS no seleccionaría la velocidad correcta y se produciría un error. Como al introducir un disco nuevo en la unidad lo primero que hace el DOS es consultar su sector de arranque, las primeras versiones de 2M dejaban la tarea de detectar la densidad del disco a la propia BIOS (espiando las lecturas del sector de arranque que ésta realizaba para determinar el tipo de disco y decidir si robar el control o no). Sin embargo, ciertas BIOS de prestigiosa marca italiana (yo sólo conozco una) hacían cosas muy raras para determinar la densidad de los discos (como ir leyendo varias pistas consecutivas) y tropezaban con los disquetes 2M. Esto es un botón de muestra de lo que pasa cuando los fabricantes europeos modifican mal las BIOS de los taiwaneses, para no copiarlas del todo. De ahí que la versión definitiva del programa reemplace en esta tarea a la BIOS. Sin embargo, en caso de que 2M no pueda determinar la densidad de la unidad sique delegando el control a la BIOS: el motivo es mantener la compatibilidad con otros soportes extraños. Este es también el motivo por el que 2M no sustituye totalmente el código BIOS de INT 13h, que hubiera dado menos problemas a la hora de programar (aunque el programa resultante ocuparía también algo más de memoria).

                     COPY DE 21 FICHEROS Y 1.457.664 BYTES                      
+------------------+---------+---------+---------+---------+---------+---------+
| Formato          |  1.44   |  1.44   |  1.64   |  1.72   |  1.80   |  1.88   |
+------------------+---------+---------+---------+---------+---------+---------+
| Formateador      |  FORMAT |FDFORMAT |FDFORMAT |FDFORMAT |   2MF   |   2MF   |
+------------------+---------+---------+---------+---------+---------+---------+
| Tiempo escritura | 1:17.27 | 1:06.72 | 1:00.74 | 1:27.05 | 1:15.30 | 1:23.93 |
+------------------+---------+---------+---------+---------+---------+---------+
| Tiempo lectura   | 0:59.82 | 0:48.50 | 0:44.11 | 1:05.69 | 0:43.78 | 0:54.16 |
+------------------+---------+---------+---------+---------+---------+---------+
| Espacio libre    |       0 |       0 | 203,776 | 287,744 | 370,688 | 454,656 |
+------------------+---------+---------+---------+---------+---------+---------+
| Escritura (Kb/s) |  18.42  |  21.34  |  23.44  |  16.35  |  18.90  |  16.96  |
+------------------+---------+---------+---------+---------+---------+---------+
| Lectura (Kb/s)   |  23.80  |  29.35  |  32.27  |  21.67  |  32.51  |  26.28  |
+------------------+---------+---------+---------+---------+---------+---------+
| Promedio (Kb/s)  |  21.11  |  25.35  |  27.86  |  19.01  |  25.71  |  21.62  |
| Indice relativo  | 100.00  | 120.09  | 131.98  |  90.05  | 121.79  | 102.42  |
+------------------+---------+---------+---------+---------+---------+---------+
      Notas:
        - Ficheros: 2 de 256K, 3 de 128K, 4 de 64K, 5 de 32K, 6 de 16K y 1 de 15.5K.
        - Prueba bajo DOS 6.2 y con solo 2M y FDREAD instalados.
        - La prueba de escritura consistía en COPY C:\TEST\*.* B: y la de lectura
          consistía en COPY /B *.* NUL
        - Al leer del disco duro se perdieron 5.5 segundos que han sido ya descontados;
          el disco ya estaba girando.
        - Con FDFORMAT se emplearon siempre los parámetros /X:2 e /Y:3 para lograr
          la mayor velocidad posible.

     La rutina calc_chk es quien realmente realiza el checksum del sector de arranque, comprobando además si el disco es de tipo 2M. La rutina set_err, invocada al final del formateo y desde la rutina que accede directamente a los sectores de disco, analiza el código de error devuelto por el controlador de disquetes y lo convierte a la notación de errores de la BIOS. Set_bios_err copia el resultado del acceso a disco a las variables propias de la BIOS por razones de compatibilidad con el software de disco de bajo nivel.

     En el procedimiento control_2m se realiza la gestión a alto nivel del acceso a disco: es aquí donde se emula la existencia de la segunda copia de la FAT apoyándose en la primera, así como el sector de arranque virtual ubicado en el primer sector físico de la FAT2. Como 2M 2.0 apareció cuando ya estaba bastante extendida la versión anterior, se hizo necesario (y lo sigue siendo en 2M 3.0) continuar soportando los discos antiguos. En ellos, se sigue leyendo el sector de arranque físico en lugar del virtual, que no existe, y se permite su escritura si es correcto (si no se intentan tocar partes sensibles del mismo). Así mismo se tiene en cuenta el acceso al cabezal 128 ó 129 para acceder en ese caso al 0 ó al 1 sin emulaciones. Las coordenadas de la BIOS, en la forma cilindro-cabezal-sector son traducidas momentáneamente a las del DOS para simplificar el proceso. También se comprueba si el checksum (o suma de comprobación) del sector de arranque, realizado con anterioridad en set_info, es correcto. Es difícil que no lo sea, porque el código de 2M no deja a cualquiera escribir sobre el sector de arranque físico. Pero si no lo fuera, se devuelve un seek error al programa que llama a la INT 13h, habiéndose elegido este código porque no había otro más descriptivo en la lista de errores de disco de la BIOS. Si al ejecutar un comando DIR sobre un disquete 2M aparecen errores de seek ya sabrá el lector por qué...

     El procedimiento ejecuta_io es llamado repetidamente desde control_2m para realizar la lectura o escritura de un conjunto de sectores. Este procedimiento es el más complicado de todo el programa, pero la tarea que realiza es relativamente sencilla. Primero, vuelve a pasar las coordenadas del disco del formato DOS al formato físico propio de la BIOS. Hay que tener en cuenta que un sector físico en un disquete 2M puede ser de 512 bytes, pero también de 1024 ó 2048. Por tanto, introducimos aquí el concepto de sección para hacer referencia a 512 bytes, que a fin de cuentas es la unidad de medida a emplear.

     En el caso de los formatos de mayor capacidad (2MF /M) se accede de sector en sector físico, ya que las operaciones de lectura/escritura de varios sectores en bloque sólo tienen sentido cuando éstos están lo suficientemente separados pero sin pasarse. En nuestro caso están excesivamente separados, ya que la numeración es discontinua (interleave 1:2) y entre dos sectores de número consecutivo hay otro; por tanto, no se ganaría rendimiento en un acceso multisector; por otro lado, algunos formatos de disco tienen un número par de sectores en las pistas y dos de ellos tienen que tener forzosamente el número consecutivo, con lo que fallaría el acceso multisector debido a la excesiva proximidad en este caso; además, no está muy claro si se podrán acceder de esta manera sectores que no sean del mismo tamaño (no me molesté en probarlo). La lectura es la operación más sencilla: se extrae del disco el sector físico donde está incluida la sección que toca leer y después se copia a la dirección de memoria definitiva. No se puede leer el sector directamente en el buffer requerido por el programa que invoca la INT 13h, ya que éste podría requerir sólo 512 bytes (o un múltiplo impar de esta cifra) y los sectores físicos podrían exceder este tamaño, afectando a zonas no permitidas de la memoria ubicadas tras el buffer. Por tanto se utiliza un buffer intermedio (definido con un tamaño de 2 Kb para acomodar el mayor sector posible). El movimiento de la sección a su ubicación definitiva no es una tarea muy costosa, ya que en un ordenador medio se ejecuta unas cien veces más rápido que lo que ha tardado la lectura desde el disco. Este proceso de lectura se repite tantas veces como secciones haya que transferir. En todo momento, unas variables indican qué sector físico (y de qué cilindro, cabezal y unidad) está en el buffer. De este modo, por ejemplo, cuando se lee un sector de 2 Kb para transferir su primera sección, se traen a la memoria 4 secciones de golpe y ya no serán necesarios más accesos a disco si hubiera que transferir también las 3 restantes, porque el sector en que están ya se encuentra en el buffer. La escritura es algo más compleja, y hay que distinguir dos casos: por un lado, cuando hay que volcar a disco un número de secciones consecutivas suficientes para completar un sector físico; por otro, cuando hay que escribir una o varias secciones que no completan un sector físico. En el primer caso, se escribe sin más; en el segundo caso es necesario leer el sector al buffer, modificar sólo la(s) seccion(es) afectada(s) y escribirlo en el disco. Este último caso supone una fuerte degradación de la velocidad, ya que tras leer un sector del disco habrá que volver a escribirlo, hecho que no ocurrirá hasta la siguiente vuelta del mismo. Por fortuna, cuando se hace un COPY el DOS envía grandes bloques, lo que en la mayoría de los casos (no en todos) provoca escrituras de pistas completas, tarea en la que no se pierde un ápice de rendimiento. No obstante, esta arquitectura de los disquetes 2M provoca que sean notablemente más lentos escribiendo que leyendo.

+--------------------------------------------------+
| MAPAMEM 2.1                                      |
|   - Información sobre la memoria del sistema.    |
|                                                  |
| Tipo     Ubicación Tamaño   PID    Propietario   |
| -------- --------- ------- ----- --------------- |
| Sistema  0000-003F   1.024        Interrupciones |
| Sistema  0040-004F     256        Datos del BIOS |
| Sistema  0050-0105   2.912        Sistema Operat.|
| Sistema  0107-0143     976  0008                 |
| Sistema  0145-0144       0  0008                 |
| Sistema  0146-0149      64  0008                 |
| Programa 014B-015A     256  014B  4DOS           |
| Entorno  015C-0174     400  0176  MAPAMEM        |
| Programa 0176-01C9   1.344  0176  MAPAMEM        |
| Libre    01CB-9FFE 648.000  0000  <Nadie>        |
| Sistema  A000-D3B4 211.792  0008                 |
| Sistema  D3B6-D3C2     208  D3B6                 |
| Sistema  D3C4-D50D   5.280  D3C4                 |
| Sistema  D50F-E437  62.096  0008                 |
| Sistema  E439-E49C   1.600  E439                 |
| Sistema  E49E-E4AD     256  E49E                 |
| Sistema  E4AF-E4CE     512  E4AF                 |
| Sistema  E4D0-E55E   2.288  E4D0                 |
| Sistema  E560-E568     144  E560                 |
| Datos    E56A-E631   3.200  014B  4DOS           |
| Entorno  E633-E672   1.024  014B  4DOS           |
| Libre    E674-E68C     400  0000  <Nadie>        |
| Programa E68E-E810   6.192  E68E  SHARE          |
| Programa E812-E97A   5.776  E812  PRINT          |
| Entorno  E97C-E996     432  E998  VIDRAM         |
| Programa E998-EA04   1.744  E998  VIDRAM         |
| Entorno  EA06-EA1F     416  EA21  UNIVESA        |
| Programa EA21-EBF1   7.440  EA21  UNIVESA        |
| Programa EBF3-EC1D     688  EBF3  KEYBSP         |
| Programa EC1F-EC77   1.424  EC1F  RCLOCK         |
| Programa EC79-EDBB   5.168  EC79  2M             |
| Programa EDBD-EDD8     448  EDBD  DISKLED        |
| Libre    EDDA-EDF3     416  0000  <Nadie>        |
| Programa EDF5-F281  18.640  EDF5  DATAPLUS       |
| Programa F283-F34D   3.248  F283  HBREAK         |
| Programa F34F-F354      96  F34F  TDSK(D)        |
| Datos    F356-FB55  32.768  F34F  TDSK(D)        |
| Libre    FB57-FFA5  17.648  0000  <Nadie>        |
+--------------------------------------------------+
                              MEMORIA OCUPADA POR 2M

     En los formatos normales (2MF /F) todos los sectores de la pista son del mismo tamaño, lo que también sucede en la primera pista de los formatos de más capacidad. Están suficientemente separados y numerados consecutivamente. Por tanto, una acceso multisector es posible y más que interesante. Aquí no sólo no se emplea el buffer intermedio sino que además no se puede, porque el acceso multisector puede superar los 2 Kb de capacidad del buffer. La transferencia se hace directamente sobre la dirección deseada por el programa que invoca la INT 13h. Sólo hay un par de excepciones: cuando la primera sección a transferir es la segunda mitad de un sector (recordemos que son de 1 Kb) y cuando la última sección es la primera mitad de un sector. En ambos casos se emplea el buffer intermedio por el mismo motivo de siempre: evitar la alteración de zonas de memoria que vayan detrás del buffer suministrado por el programa que llama a la INT 13h. Sobre la escritura se podrían hacer las mismas consideraciones que hacíamos con los formatos de máxima capacidad. En la operación de acceso multisector hay que considerar también el posible cruce del buffer suministrado por el programa principal con una frontera de DMA: la rutina acceso_multi se encarga, llegado el momento, de transferir el sector crítico a través del buffer intermedio, segmentando la operación en tres fases (los sectores anteriores, el sector que cruza la frontera y los restantes). No controlar los problemas con el DMA provoca que el ordenador se cuelgue al hacer COPY de un fichero mediano (o que lo copie mal en cualquier caso). Obviamente, el buffer intermedio se inicializa para que nunca cruce una frontera de DMA. El único caso en que acceso_multi no necesita tomar precauciones con el DMA es en el código SuperBOOT: aunque se instale desde la INT 13h, lo hace antes de la carga del sistema operativo (que será el encargado de arreglar los problemas con el DMA).

     Por tanto, en ejecuta_io es donde se toman todas las complicadas decisiones sobre cómo y dónde cargar/grabar de disco. He de agradecer aquí a Edgar Swank su colaboración en detectar y corregir errores en esta compleja rutina, proponiéndome además las modificaciones en el listado: antes de 2M 2.0, los discos 2M no soportaban realmente la escritura con verificación (VERIFY ON a nivel DOS). La variable sector_fin está a 0 para indicar el acceso a un solo sector (sector_ini) o es distinta de cero para indicar el último sector involucrado en el caso de accesos multisector (junto a sector_ini). Dentro de este procedimiento, la subrutina acceso_secc se encarga de la transferencia de una sola sección.

     El procedimiento trans_secc realiza las transferencias entre el buffer interno y la dirección suministrada por el programa que llama a la INT 13h. La rutina leido? comprueba si el próximo sector físico a ser accedido esta ya en el buffer, para evitar una segunda lectura innecesaria.

     El procedimiento acceso_sector se encarga de hacer ciertas tareas como determinar la longitud del sector a ser leído (para poder programar luego correctamente el FDC), llevar el cabezal a la pista adecuada, cargar los registros convenientemente según haya que emplear el buffer intermedio o no, llamar a la rutina que accede realmente al disco y tomar nota de qué sector ha sido recién leído (para evitar futuras lecturas innecesarias).

     En num_secciones se calcula el número de secciones o bloques de 512 bytes del sector físico en curso, apoyándose en la información del sector de arranque del disquete que fue anotada cuando se le reconoció por vez primera.

     La rutina motor_ok arranca el motor de la unidad si aún no estaba en marcha. En caso de estar parado, o de llevar poco tiempo encendido a causa de una reciente lectura de la línea de cambio de disco (el contador de tiempo que resta para su detención es aún muy alto) se hace la pausa pertinente para que alcance el régimen de rotación adecuado. Esta rutina es invocada en varias ocasiones; entre otras, desde ejecuta_io.

+-------------------------------------------------------------------+
|                                                                   |
|  [14464/109040] C:\>dir b:                                        |
|                                                                   |
|   Volume in drive B is unlabeled      Serial number is EA82:3F1B  |
|  File not found "B:\*.*"                                          |
|             0 bytes in 0 file(s)                                  |
|     1.912.320 bytes free                                          |
|                                                                   |
|  [14464/109040] C:\>diskcopy b: b:                                |
|                                                                   |
|  Inserte el disquete de ORIGEN en la unidad B:                    |
|                                                                   |
|  Presione cualquier tecla para continuar . . .                    |
|                                                                   |
|  Copiando 82 pistas                                               |
|  23 sectores por pista, 2 cara(s)                                 |
|                                                                   |
|  Inserte el disquete de DESTINO en la unidad B:                   |
|                                                                   |
|  Presione cualquier tecla para continuar . . .                    |
|                                                                   |
+-------------------------------------------------------------------+
                    LA COMPATIBILIDAD DE 2M ES PRACTICAMENTE DEL 100%

     En reset_drv se inicializa el FDC enviándole el comando Specify; la situacion de reset es mantenida durante unos microsegundos, pausa que también realizan las BIOS modernas, ya que en algunas versiones de 2M anteriores a la 1.3 se comprobó que no lograban resetear la controladora en algunas máquinas 486 (en estos casos no se detectaba el tipo del nuevo disco introducido en la disquetera y, al delegar el control a la BIOS, ésta generaba errores de sector no encontrado y anomalía general con los disquetes 2M).

     La rutina seek_drv posiciona el cabezal seleccionado sobre el cilindro adecuado: si ya estaba sobre él (por haber accedido con anterioridad a la otra cara del disco) no es necesario esperar a que el cabezal deje de vibrar; en caso de que haya que hacer esta pausa se establecen 1 ms para el caso de la lectura (no es muy peligroso que se produzca un error, ya que la operación se reintentaría) y 15 ms para la escritura, asegurando en este último caso el éxito de la operación, ya que escribir con el cabezal no asentado podría dañar la información del disco. El disco está formateado (salvo en los los formatos de máxima capacidad, que son un mundo aparte) con ciertos deslizamientos en la numeración de los sectores al conmutar de cilindro y cabezal (opciones /X e /Y del formateador) de tal manera que el acceso en escritura es factible en una sola vuelta del disco para todas las pistas a las que se acceda consecutivamente. Rebajar a 1 ms en el caso de la lectura tiene por objeto asegurar esto mucho más todavía. Así, algún ordenador muy extraño que pinchara en los índices de rendimiento a la hora de escribir probablemente no lo haría, al menos, al leer. Como un posicionamiento del cabezal precede siempre a las operaciones de lectura o escritura (seek_drv), se selecciona aquí la velocidad de transferencia a emplear, acorde con la densidad de la pista a ser accedida (set_rate). En caso de que la unidad precisara recalibración (debido a algún reset anterior) se llama desde aquí al procedimiento recalibrar.

     El procedimiento sector_io es quien finalmente se encarga de hacer la lectura o escritura del sector o sectores necesarios, programando el FDC. Se calcula el tamaño en bytes del bloque a transferir, se programa el DMA por medio de las rutinas calc_dir_DMA y prepara_DMA y se envía el comando adecuado al FDC (lectura/escritura). Al final, se anotan los resultados. La subrutina calc_dir_DMA traduce la dirección segmentada al formato necesario para programar el DMA; en el código SuperBOOT tiene que devolver además un posible error de cruce de frontera de DMA, ya que el código de 2M no evita las llamadas ilegales en este caso.

     En genera_info se construye la tabla de información a enviar al DMA para formatear la pista solicitada en la función de formateo de 2M. Esta información se obtiene a partir del sector de arranque del futuro disco, suministrado por el programa que intenta formatear. Conociendo cómo esta estructurado dicho sector, la arquitectura de los disquetes 2M y qué necesita el comando del FDC para formatear se puede entender cómo funciona la rutina, por lo que no nos detendremos en analizarla. Es formatea_pista el procedimiento que formatea la pista a partir de la tabla creada por la rutina anterior.

     La subrutina espera_int espera durante no más de 2 segundos la llegada de una interrupción de disquete que señalice el final de una operación con el FDC. Conviene no esperar indefinidamente porque si la unidad no está preparada podría tardar muchísimo en devolver la interrupción. Así, se detecta en un tiempo razonable la circunstancia y posteriormente se reseteará la controladora (ante el error) para arreglar el problema de la interrupción pendiente (y del FDC que no respondía). Fdc_read y fdc_write se encargan de recibir y enviar bytes al FDC, típicamente órdenes y resultados. Ambas rutinas también tienen control timeout, en este caso de 2 milisegundos; al principio de las mismas se realiza una brevísima pausa al igual que hacen las BIOS AMI de 486 (que para algo servirá). Finalmente, las subrutinas fdc_respiro y retardo efectúan una pausa de 60 mus y AX milisegundos, respectivamente, apoyándose repetitivamente en la macro pmicro, que pierde unos 15,09 microsegundos muestreando los ciclos de refresco de memoria del AT. Pmicro no es una subrutina (salvo en el caso del código SuperBOOT, por razones de espacio) porque el CALL y RET asociados podrían ralentizar la monitorización de los ciclos de refresco de manera excesiva en los ordenadores más lentos, deparando un retardo efectivo superior.

     Finalmente, initcode será invocada sólo desde el sector de arranque físico durante el arranque desde disquete, con objeto de inicializar ciertas variables y activar el código SuperBOOT. Una precaución importante es que, ensamblando para obtener código SuperBOOT, éste tiene que ocupar exactamente 2560 bytes (5 sectores). Ciertamente, entra muy justo... pero cabe, con alguna que otra artimaña (excluir rutinas de formateo, utilizar subrutinas en vez de macros, simplificar la gestión de las fronteras de DMA, etc) aunque los 5 sectores que ocupa impiden ubicarlo en discos de doble densidad. Pero, ¿quién va a querer hacer botable un disco 2M de doble densidad, cuando uno estándar de alta tiene más capacidad?.


12.6.7.4 - DESCRIPCION DEL PROGRAMA DE FORMATEO (2MF) PARA 2M.

     El formateo de los disquetes 2M puede realizarse desde un lenguaje de alto nivel por medio de las funciones de la BIOS implementadas por 2M cuando está residente. El siguiente programa de ejemplo demuestra lo sencilla que es esta tarea. El único problema importante que se presentó durante su desarrollo fueron los conflictos que generaba WINDOWS al intentar formatear un disco en el formato de máxima capacidad (opción /M): por algún motivo, era imposible crear este tipo de pistas al producirse un extraño error en la función de formatear. Este problema ya se había presentado en versiones anteriores de 2M, que también formateaban los discos. La solución adoptada es, sencillamente, invocar la INT 13h mediante un CALL a la dirección del vector de interrupción. De este modo no se ejecuta el código WINDOWS responsable de la incompatibilidad, que entraba en marcha al llamar a la INT 13h en modo protegido. Tenga en cuenta el lector que una inocente instrucción INT es mucho más que eso bajo WINDOWS o con un controlador de memoria instalado. Este fragmento de código de 2MF ha sido codificado en ensamblador, entre otros motivos porque antes de llamar con CALL a una interrupción hay que apilar los flags y eso resulta difícil en C. Durante las restantes fases del formateo (lectura para verificar y la escritura previa en los formatos de máxima capacidad) se utilizan las funciones estándar de la BIOS vía INT 13h. Aunque WINDOWS no estorbara, tampoco hubiera sido posible llamar con la función de formateo BIOS del compilador, ya que los parámetros cambian ligeramente, si bien se podría haber hecho con código C.

     El programa admite varios parámetros para controlar el formateo. Por defecto realiza el formateo normal, más fiable (o indicando la opción /F). Para seleccionar el formateo de máxima capacidad hay que indicar /M. Desde 2MF 3.0, el programa es capaz de detectar la densidad en discos de 3½ vírgenes (con la excepción de las unidades que permiten formatear en alta densidad los discos de doble) y lo intenta en los de 5¼ (sólo funciona si ya tenían algún tipo de formato previo). En cualquier caso, siempre se puede indicar la opción /HD, /DD ó /ED para seleccionar la densidad necesaria y evitar la pequeña pérdida de tiempo en detectarla.

     El número de pistas, por defecto 82, puede elegirse con /T, ya que muchas unidades soportan 84 pistas o más; de todas maneras, 2MF 3.0 no permite formatear más pistas de las que admita la unidad, al contrario que las versiones anteriores. Los ficheros permitidos en el directorio raíz se indican con /R. El parámetro /S evita la producción de sonido. Con /N se evita la verificación, /K y /J eliminan la pausa inicial y final, respectivamente; /Z anula el parpadeo del led mientras se cambia el disco y /L y /V permiten poner etiquetas de volumen (serializadas en el último caso) al disco destino.

     Finalmente, hay varios parámetros no documentados oficialmente que no deberían ser alterados, salvo quizá en algún ordenador muy concreto y por parte de usuarios muy especializados, que permiten elegir los factores de desplazamiento en la numeración de los sectores al conmutar de cabezal (/X) y de cilindro (/Y) en el formato normal (/F); en el formato de máxima capacidad (/M) no tienen efecto. El parámetro /G permite indicar el GAP o separación de sectores en todas las pistas -salvo la primera- en el formato /F; en el formato /M este valor de GAP se refiere al GAP empleado en la primera pasada del formateo (con sectores de 128 bytes). Con /D0 se formatea en 3½-DD con 820/902K (en lugar de 984/1066K), algo necesario en las controladoras de algunos portátiles que no soportan la densidad de 300 Kbps (propia exclusivamente de las unidades de 5¼); si bien no es preciso emplearlo ya que por defecto el programa formatea de esta manera en esas unidades al autodetectar la densidad del disco destino. /D1 formatea 1148K en lugar de 1066K, pero el disco resultante es poco seguro y extremadamente lento. Por último, la opción /W hace que se marquen sólo los clusters defectuosos y no la pista completa.

        +-------------------------------------------------------------------------------+
        |                        TIEMPO EMPLEADO EN EL FORMATEO                         |
        +---------------+---------------+---------------+---------------+---------------+
        |    FORMAT     | FDFORMAT (*)  | FDFORMAT (**) |  2MF 3.0 /F   |  2MF 3.0 /M   |
+-------+---------------+---------------+---------------+---------------+---------------+
| 5¼-DD |      0:37     |      0:42     |      1:28     |      1:26     |      2:37     |
| 5¼-HD |      1:13     |      1:24     |      1:52     |      1:29     |      2:38     |
| 3½-DD |      1:24     |      1:38     |      1:46     |      1:39     |      2:51     |
| 3½-HD |      1:34     |      1:42     |      2:17     |      1:47     |      3:22     |
+-------+---------------+---------------+---------------+---------------+---------------+
 (*) Usando el formato estándar del DOS (360-720-1.2-1.44) y los parámetros /X e /Y adecuados.
(**) Formatos de máxima capacidad soportados (820-1.48-1.72) y los parámetros /X e /Y adecuados.

     La parte más compleja del programa es la función CrearSector0(), que como su propio nombre indica se encarga de crear el sector de arranque del futuro disquete. En un programa de copia de discos esta función no sería necesaria, ya que al leer el disquete origen tendríamos ya el sector de arranque del futuro disquete destino y, por tanto, podríamos formatearle directamente (recordar que la función de formateo de discos 2M sólo necesita como parámetro el sector de arranque del futuro disco). Sin embargo, aquí nos vemos obligados a crear dicho sector, lo cual es una tarea un tanto engorrosa, teniendo en cuenta la variedad de formatos. Una tabla más o menos complicada, de 5 dimensiones, contiene toda la información necesaria para la tarea. Además, el código ejecutable del sector de arranque resultaba difícil incluirlo dentro del listado C y finalmente se optó por crear un fichero proyecto e incluir en él 2MF.C y 2MFKIT.ASM (este último integra los sectores de arranque para alta y doble densidad -con y sin soporte SuperBOOT, respectivamente- así como el código SuperBOOT y las rutinas de utilidad).

     Durante el proceso de formateo, en FormatearDisco() se está pendiente de una posible pulsación de la tecla ESC. Se controlan los posibles errores fatales, tales como unidad protegida de escritura o no preparada, que suponen el fin del proceso de formateo, pero se toleran los demás errores -si no afectan a las áreas del sistema del disco- marcando los clusters afectados como defectuosos si al tercer intento de formateo siguen fallando. Al final del formateo, en InformeDisco() se imprimen las características del nuevo disquete pero sin emplear funciones del DOS. Realmente, el DOS ya se ha dado cuenta del cambio de disco e informaría correctamente, pero de esta manera se asegura a ultranza que la información es correcta.

     La función TipoDrive() devuelve el tipo de la disquetera que se le indique consultando esta información a través de la BIOS. La función InicializaDisco() escribe, al final del formateo, el sector de arranque físico, el virtual, el código SuperBOOT (si el disco es de alta densidad) y la FAT; de esta última sólo la primera copia, ya que 2M emulará la segunda.

     Las funciones de sonido crean efectos especiales bastante atractivos gracias al empleo de retardos de medio milisegundo con la función PicoRetardo(); este retardo es idéntico en todas las máquinas, con total independencia de la velocidad de la CPU, y permite que el sonido suene igual en todas. En los PC/XT no se realiza retardo alguno y, curiosamente, el sonido suena igual que en los AT (en máquinas de 8 MHz).

     La función EsperarCambioDisco() espera a que se retire el disquete de la unidad y se introduzca uno nuevo, o bien a que se pulse una tecla (considerando el caso de ESC, para abortar el formateo). Esto permite formatear varios disquetes introduciéndolos unos tras otros en la unidad sin necesidad de pulsar teclas. En WINDOWS se puede abrir una ventana para formatear disquetes 2M y, dejándola en la sombra, cada vez que se oiga el sonido de fin de formateo, sin abandonar lo que se tenga en ese momento entre manos, se puede sacar el disco e introducir otro para que el proceso continúe automáticamente sin tener que activar la ventana para pulsar una tecla. El sonido de final de formateo permite distinguir entre un formateo correcto y otro con errores (se considera correcto aunque haya sectores defectuosos, lo de errores va por lo de disco protegido contra escritura, etc.). Las rutinas de bajo nivel que acceden a la controladora de disco en 2MF lo hacen, exclusivamente, para conseguir el efecto intermitente en el led de la unidad mientras se cambia de disco (y para reducir el ruido que emite la función de detección de nuevo disco de la BIOS).

     Para fomentar que los usuarios envíen la postal al autor, el programa tiene un contador de discos formateados añadido cuando formatea el primer disco por el método de alargar el tamaño del fichero EXE. Al cabo de 100 discos, imprime un mensaje recordando al usuario su deber. Naturalmente, si 2MF se ejecuta desde una unidad protegida contra escritura, no será posible actualizar el contador...

     Finalmente, la función HablaSp() comprueba el país en que se ejecuta el programa para inicializar una variable global que indique si los mensajes han de ser imprimidos en castellano o en inglés.


12.6.7.5 - UN PROGRAMA PARA MEDIR EL RENDIMIENTO DE LOS DISQUETES.

     En las páginas donde se describía el funcionamiento de 2M aparecía una tabla con los tiempos cronometrados de un COPY de múltiples ficheros, desde y hacia un disquete en los formatos de disco más comunes. Sin embargo, resulta interesante conocer la velocidad real del sistema de disco cuando éste es utilizado óptimamente: acceso a múltiples pistas completas y consecutivas en el disco. Los buenos programas de copia de discos, que leen de un golpe todas las pistas consecutivas que pueden antes de guardarlas en un fichero auxiliar (o que las almacenan en EMS ó XMS), dependerán de la velocidad que sea capaz de dar el formato de disco empleado, ya que las disqueteras giran a una velocidad fija en todos los ordenadores. Si pierden tiempo entre pista y pista (tal vez por escribirlas en el fichero auxiliar una por una) la velocidad obtenida podría dividirse por dos, al intentar pillar el primer sector de la siguiente pista justo cuando acaba de pasar de largo por delante del cabezal.

        +--------------------------------+-------------------------------------------------------------------------------+
        | Velocidad máxima teórica sin   |          Velocidad real en Kb/seg estimada por 2M-FDTR (nivel BIOS).          |
        | considerar tiempos de acceso   +---------------+---------------+---------------+---------------+---------------+
        | pista-pista ni el porcentaje   |    FORMAT     | FDFORMAT (**) | FDFORMAT (***)|  2MF 3.0 /F   |  2MF 3.0 /M   |
        | de superficie magnética  que   +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
        | se aprovecha en cada  pista.   | Lect. | Escr. | Lect. | Escr. | Lect. | Escr. | Lect. | Escr. | Lect. | Escr. |
+-------+--------------------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
| 5¼-DD |  36,62  Kb/seg  (300 Kbit/seg) | 18.16   18.16 | 22.11   22.12 | 25.00   25.00 | 25.04   25.00 | 16.49   16.49 |
| 5¼-HD |  61,03  Kb/seg  (500 Kbit/seg) | 30.13   30.13 | 39.73   39.73 | 25.26   25.23 | 46.33   46.33 | 28.50   28.47 |
| 3½-DD |  30,52  Kb/seg  (250 Kbit/seg)*| 15.05   15.05 | 19.32   19.32 | 21.78   21.75 | 25.72   25.76 | 16.25   16.25 |
| 3½-HD |  61,03  Kb/seg  (500 Kbit/seg) | 30.14   30.14 | 39.58   39.53 | 24.79   24.79 | 48.49   48.50 | 28.74   28.77 |
+-------+--------------------------------+---------------+---------------+---------------+---------------+---------------+
                               (*) 2M emplea 300 Kbit/seg (no es compatible con controladoras de doble densidad de PC/XT).
                            (**) Usando el formato estándar del DOS (360-720-1.2-1.44) y los parámetros /X e /Y adecuados.
                         (***) Formatos de máxima capacidad soportados (820-1.48-1.72) y los parámetros /X e /Y adecuados.

     Con objeto de uniformizar los índices, el siguiente programa de ejemplo realiza la lectura y escritura completa de un disco (en este último caso, si no contenía datos, ya que se estropearían) llamando a la BIOS. La primera versión del programa empleaba el DOS (funciones absread() y abswrite() del C) y obtenía exactamente los mismos índices, aunque problemas de fiabilidad aconsejaron utilizar funciones de la BIOS, con lo que el programa ya no puede, por ejemplo, analizar el rendimiento de un disco duro (debido a la incomodidad que supone buscar el sector de arranque a través de la tabla de particiones). Se recorren en lectura y escritura todos los cilindros del disco, a partir del 1 y llegando hasta el último que exista. El motivo de saltar el cilindro 0 es doble: por un lado, saltar las áreas del sistema (de cara a no escribir sobre el sector de arranque, por ejemplo, ya que por simplicidad se escribe basura y no lo que se ha leído al principio); por otro lado, los tiempos de este cilindro pueden ser diferentes de los obtenidos en los demás cilindros, bien debido a la interferencia del sistema o los programas de caché o, simplemente, porque tiene un formato físico muy especial (como es el caso de los disquetes 2M). En el caso de los disquetes 2M, de esta forma no se tiene en cuenta el tiempo extra que se pierde en este primer cilindro debido a la extraña maniobra que supone simular la existencia de la segunda copia de la FAT (que implica volver momentáneamente al primer cabezal después de haber pasado al segundo).

     El programa, 2M-FDTR (2M Floppy Data Transfer Rate), utiliza el contador de hora de la BIOS unido al temporizador 8254 para cronometrar. Antes de comenzar el test y arrancar el cronómetro se lee uno de los últimos sectores del cilindro 1 para asegurar que el cabezal está ya sobre el mismo y a punto de pillar el primer sector. El buffer donde se realizará la lectura/escritura es asignado de tal manera que no cruce una frontera de DMA (para que INT 13h no tenga que segmentar en varias fases la operación, lo que disminuiría la velocidad). El acceso a INT 13h se realiza de manera directa, ya que la versión 3.1 del compilador hace alguna oscura maniobra con biosdisk y al final termina perdiendo demasiado tiempo (lo suficiente como para que en alguna máquina el disco aparente ser más lento de lo que realmente es). Con Borland C 2.0 no hay problemas, pero...



12.6.7.6 - LA VERSION PARA PC/XT DE 2M: 2MX  [Listado no incluido en este libro].

     Aunque 2M fue inicialmente concebido para máquinas AT, a partir de la versión 1.2 ha estado acompañado de una versión para PC/XT. El único requisito es que el ordenador esté equipado con una controladora y unidades de alta densidad. Algunas máquinas modernas de tipo subnotebook, que caben en la palma de la mano, vienen preparadas para conectar una de estas disqueteras externas. Otros PC/XT de reciente fabricación traen ya controladoras de alta densidad y BIOS que las soportan, aunque luego el tacaño fabricante haya colocado una unidad de doble densidad que el usuario puede sustituir. Finalmente, a aquellas máquinas más antiguas que no pertenecen a ninguna de estas dos categorías, se les puede sustituir la controladora y unidades de doble densidad por otras de alta, que en el futuro el usuario podrá colocar en su máquina AT cuando se la compre; se trata por tanto de una inversión rentable. Si bien resulta difícil encontrar actualmente en el mercado controladoras de alta densidad para PC/XT, el usuario puede optar por poner una de AT. Yo, por ejemplo, para probar 2MX me vi obligado a pinchar una controladora de 16 bits en un slot de 8 bits. La tarjeta era una IDE multi-io; sin embargo, la parte alta del bus (que no se puede pinchar al ser de 8 bits el slot) sólo se utiliza para acceder al disco duro bus AT, pudiendo ser inhibida con el jumper de marras (si bien ni esto resultó necesario). La parte correspondiente al control de disquetes, y probablemente los puertos serie/paralelo, era totalmente funcional, ya que sólo opera con la mitad baja del bus.

     El principal problema radica en que la BIOS de los PC/XT en el 99% de los casos no está preparada para soportar alta densidad. Al hacer DIR sobre un disquete de alta densidad nada más encender el ordenador, lo más probable es que funcione, ya que ésta es la densidad por defecto normalmente. Sin embargo, con los discos de doble densidad (donde tiene que seleccionar 250 ó 300 Kbit/seg) es imposible sacar el DIR. En cualquier caso, sacar un DIR es una cosa y otra muy diferente conseguir que el disco funcione. Como la BIOS informa siempre que todo es de doble densidad, el muy patoso del DOS modifica la tabla base del disco para indicar como 9 el último número de sector en la pista (¿quién le mandará tocar las variables de la BIOS?) por lo que ni los discos de alta densidad funcionan a nivel de COPY (el directorio sí aparece porque coincide en los primeros sectores de las pistas). La solución en este tipo de máquinas pasa por instalar una BIOS más moderna... pero sin tener que regrabar la eprom. Basta con cargar 2M-XBIOS.EXE, un programa residente que emula la BIOS AMI de AT en los XT. De hecho, 2MX solicita al usuario la instalación de este driver cuando advierte que no puede detectar el tipo de las unidades.

     En ese sentido, la combinación 2M-XBIOS + 2MX permite a cualquier máquina PC/XT obsoleta equipada con una barata controladora de disquetes de AT trabajar con discos de cualquier densidad y cualquier formato (estándar/2M). Los problemas de versiones anteriores de 2MX han sido eliminados gracias a la extensión BIOS en que se apoya. De hecho, 2MX es en sus últimas versiones prácticamente idéntico a 2M, sólo cambia en algunos aspectos puntuales relacionados con la diferente arquitectura de los XT respecto a los AT.

12.6.7.7 - LA OPCION BIOS DE 2M: 2M-ABIOS Y 2M-XBIOS  [Listados no incluídos en este libro].

     Algunos ordenadores poseen una BIOS antigua o con un diseño propio poco compatible en el control de disco. En estas máquinas, 2M y otros programas de acceso a bajo nivel pueden fallar. En dichos casos, se puede instalar esta utilidad antes que 2M, y en general que cualquier otro software que acceda al subsistema de disco. La versión 2M-ABIOS es para AT y 2M-XBIOS para PC/XT.

     Estos programas actualizan el soporte de disco flexible al nivel de las BIOS AMI de 1993. Si con ellos instalados 2M no opera de manera totalmente correcta (aunque en general 2M depende realmente muy poco de la BIOS, pero ya conozco algún caso al respecto) y en la máquina no está instalado algún otro software de disco incompatible con 2M, entonces el ordenador no es 100% compatible hardware con el estándar; esto es particularmente cierto si ni siquiera se reconocen los discos estándar del DOS.

     Esta utilidad también sirve para añadir soporte de 1.44M a máquinas con BIOS antigua, algunas de ellas incluso AT. En estos casos, el usuario debe ignorar la información sobre el tipo de la unidad que pueda reportar dicha BIOS al arrancar. El programa se carga desde el CONFIG.SYS con una sintaxis sencilla:

DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]


     El consumo de memoria es de unos 3.4-4.2 Kb de RAM, y contiene una emulación al 100% del eficaz código de control de disco de las BIOS AMI, relevando así por completo de esta tarea a la BIOS del sistema. De ahí que haya sido diseñado en este formato, para forzar al usuario a instalarlo antes de los demás programas de disco, a los que anularía por completo (ya que nunca más vuelve a llamar a la interrupción de disco anterior). En AT generalmente no hará falta indicar el tipo de las unidades (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M) pero en PC/XT casi siempre será necesario. La opción /C evita en los equipos AT ajustar la CMOS, por si la máquina en cuestión tiene un algoritmo no estándar para calcular el checksum de la misma y aparece un "Incorrect CMOS checksum" al arrancar (muy poco probable). Así mismo, si en algún momento el usuario dudara acerca de si 2M-ABIOS está controlando realmente las unidades, puede utilizar la opción /13 para asegurarlo, si bien esta opción es poco recomendable cuando no es estrictamente necesaria (se desvía también INT 13h además de INT 40h, incluso aunque detecte el soporte de esta última).

     El listado comentado de estos programas (realmente uno solo, con ensamblaje condicional en 2M 3.0) se omite porque ya hay demasiadas rutinas de acceso a disco a bajo nivel en este libro.

12.6.7.8 - LA UTILIDAD 2MDOS [Listado no incluído en este libro].

     Debido a la ineficiencia de FORMAT a la hora de crear discos rápidos y teniendo en cuenta la limitación de DISKCOPY en el sentido de no poder formatear discos destino en formato 2M, se comprende la necesidad de un sustituto de FORMAT y DISKCOPY. Sin embargo, todos los programas al respecto existentes en la actualidad, a mi juicio, son un perfecto desastre. La mayoría no son rápidos incluso con discos optimizados, por una cuestión elemental: no colocar los buffers de transferencia de manera que no crucen las fronteras de DMA (para evitar que el DOS tenga que hacer accesos redundantes para salvarlas). La mayoría, de hecho, no generan discos optimizados con la clásica técnica de Sector Sliding (que en absoluto implica reducción de compatibilidad o fiabilidad; más bien al contrario: es como se debe formatear correctamente un disco y como de hecho se hace con los discos duros). Otros son poco flexibles y no soportan discos 2M (¡hasta DISKCOPY los supera en esto!) o tienen absurdas rutinas que encuentran virus en sectores de arranque poco oficiales, o necesitan VGA y ratón (aparte de ser lentos), o no son fiables...

     La solución adoptada ha sido crear un programa residente que haga trabajar a todos los demás (con la excepción de los que también acceden directamente a la controladora de disco) de la manera adecuada. Se trata de crear una utilidad para que FORMAT o cualquier otro programa que llame a la BIOS formatee discos optimizados (aún sin saberlo) y que amplíe los formatos de disco oficiales de la BIOS para que DISKCOPY (y el DUPDISK de las Norton y programas de similar flexibilidad) sean capaces, durante el proceso de copia, de formatear el disco destino 2M si es preciso.

     Con 2MDOS instalado los discos se formatean automáticamente de manera óptima y DISKCOPY soporta el formateo de discos 2M. Incluso FORMAT puede crear discos 2M (indicando pistas y sectores) si bien el de MS-DOS (no DR-DOS) tiene problemas con los de alta densidad y necesita un parámetro opcional (de todas maneras, 2MF sigue siendo más eficiente). Además 2MDOS da soporte por defecto a disquetes no estándar, creados por la utilidad FDFORMAT y permite a FORMAT poder crear disquetes FDREAD. El programa consume 5,7 Kb en equipos sin memoria extendida o 2,5 Kb con ella (sólo 1,7 Kb si no está activo el soporte para hacer DISKCOPY hacia un disco 2M sin formato; esto es, con sólo las opciones de optimización de formateo y soporte FDREAD activas).

     Por si esto fuera poco, 2MDOS incorpora una nueva técnica para acelerar aún más los discos estándar de 1.2M y 1.44M, que recibe el nombre de DiskBoost por razones de marketing. El truco consiste en evitar la necesidad de Sector Sliding, para de esta manera alcanzar, por ejemplo, una tasa de transferencia de datos de 45 Kb/seg en 1.44M (frente a los 39 Kb/seg del Sector Sliding o los 30 Kb/seg del FORMAT habitual). El truco consiste en añadir un sector adicional en el cabezal 1 y dos en el cabezal 0, que no se usan, algo que no reduce sensiblemente el nivel de seguridad del disco (sería el equivalente en seguridad a un disco de 1.64M, por ejemplo). Los sectores adicionales, no usados, son colocados al principio de la pista. De esta manera, cuando la controladora acaba de acceder a una pista completa en el cabezal 0 (y está al inicio justo de la pista tras completar una vuelta) se conmuta al cabezal 1 para acceder a la pista siguiente. Recordemos que en el cabezal 1 había un sector no utilizado al principio: este sector pasará por delante del cabezal mientras se conmuta, pero no transcurrirá demasiado tiempo como para que no se pueda pillar el primer sector de la pista que viene inmediatamente a continuación. Cuando se acabe de leer la pista en el cabezal 1 (y se está de nuevo al inicio justo de la pista tras completar la vuelta) se conmuta al cabezal 0 pero del siguiente cilindro, algo que lleva más tiempo que antes... pero para eso ya habíamos dejado dos sectores no utilizados al inicio del cabezal 0. Por tanto, también da tiempo a pillar el primer sector.

     Con la técnica DiskBoost es factible leer o escribir un disco completo de 1.44M en poco más de 31 segundos, al emplear sólo una vuelta por cada pista. La diferencia de velocidad, contra todo pronóstico, es aún más espectacular en las operaciones COPY o XCOPY normales. Los discos de 1.2M y 1.44M creados por FORMAT con 2MDOS instalado son un 50% más rápidos en el uso normal.

     Sin embargo, 2MDOS no es la solución definitiva. Aunque es útil para que cada cual utilice sus programas de copia/formateo favoritos de manera óptima, lo ideal sería un programa de copia/formateo realmente eficiente. Con dicho programa, 2MDOS no sería necesario...

     El listado de 2MDOS tampoco se incluye en estas páginas. 2MDOS también incorpora el código SuperBOOT a los discos 2M de alta densidad que se formatean bajo su control, aunque su tarea es ampliar la funcionalidad de algunas interrupciones de la BIOS y no realiza accesos directos al hardware.

12.6.7.9 - COMO SUPERAR LOS 2.000.000 DE BYTES EN 3½: 2MGUI [Listado no incluído en el libro].

     En cierta ocasión un programa llamado 1968 llegó a mis manos. Se trataba de una utilidad para formatear discos de 1.44M a esa capacidad. Sin embargo, no funcionaba en mi unidad, ni tampoco en la de mis máquinas de uso habitual. En alguna de ellas lograba formatear (a base de reintentos ante los errores) todo el disco, pero por desgracia la primera pista quedaba mal. Nunca logré crear un disco de estos, aunque se que si lo hubiera conseguido, ese disco -como bien decía el autor en la documentación- sí podría ser leído en las demás unidades.

     El método de este programa consistía en introducir 3 sectores de 4 Kb en cada pista. El problema es que eso requiere (4096+62)*3 = 12474 bytes, sin contar los GAP entre sectores, y la mayoría de las unidades giran algo más deprisa de lo normal (y por tanto, se alejan del límite teórico de 12500 bytes por pista). Por otro lado, 26 bytes son incluso pocos para respetar las marcas de inicio de pista y demás. Al final, el tercer sector suele acabar pisando al primero.

     Después de algún tiempo, han aparecido más formateadores que soportan (o dicen soportar) este formato, alguno incluso en nuestro país. Sin embargo, todos tienen el mismo problema: no hay unidades que soporten a esos programas. Por tanto, todo parecía indicar que el límite de capacidad se quedaría para siempre en los 1.72M del FDFORMAT ó los 1.88M de 2M, únicos formatos soportados por todas las unidades y ordenadores (eso sí, compatibles). Pues no. Cierto día, Jesús Arias tuvo una idea genial y me la contó. A raíz de esa idea, y tras superar numerosas y difíciles trabas técnicas, finalmente ha sido posible el milagro: lograr utilizar toda la capacidad disponible en la pista del disco, como si estuviera sin formatear.

     El programa que realiza esto, 2MGUI (abreviatura de 2M-Guinness), es ya una realidad. Durante su desarrollo se han puesto de relieve circunstancias curiosas. Por ejemplo, una determinada unidad admite 12440 bytes por pista al grabar información aleatoria, pero si se escribe toda la pista con bits a 0 ó a 1 sólo caben 12405 bytes. ¿Por qué?: la respuesta sigue siendo un misterio. Las rutinas residentes de 2MGUI aprovechan las terminaciones normales de error de la controladora (disco protegido contra escritura, sector no encontrado, etc.) para la detección de errores, aunque graban adicionalmente, en cada pista de datos, un checksum de la información almacenada junto al número de pista y cabezal reales, para realizar el control de errores cuando la controladora no puede devolver condiciones de error (debido a una serie de factores técnicos). De esta manera, la información se graba y recupera con la seguridad de que es correcta -en caso contrario, se detectaría el fallo-.

     Realizando pruebas, la capacidad admitida por diversas unidades se mostró directamente relacionada con la velocidad de rotación de la misma. Por ejemplo, una unidad de 3½-HD que gire cada 199,9 ms admite 12405 bytes, mientras que otra que lo hace cada 199,1 ms sólo admite 12348 bytes. Ambas son casos realmente extremos, ya que la inmensa mayoría se encuentra entre estas dos. Aún así, la capacidad finalmente adoptada por 2MGUI serán 12329 bytes. El objetivo es permitir que los discos puedan ser intercambiados entre unidades. En lectura nunca hay problemas, ya que la peor unidad puede leer los datos de la mejor (la que más lentamente gire) porque la señal de reloj la obtiene de los propios datos registrados en disco. Sin embargo, al escribir, la señal de reloj la extrae de su base de tiempos propia (casi igual en todos los ordenadores) y al girar más deprisa se le acaba la pista antes y sobreescribe el principio. Por tanto, los discos que apuren demasiado la capacidad de una buena unidad serán estropeados al ser escritos (no leídos) en otra unidad peor.

                                +-----------+-----------+------------+       
                                |   Doble   |   Alta    | Extraalta  |       
+-------------------------------+-----------+-----------+------------+------+
| Récord absoluto previo a 2M   |  820.0 Kb | 1394.0 Kb |     --     |      |
| Capacidad máxima 2M (2MF /M)  |  902.0 Kb | 1558.0 Kb |     --     | 5.25 |
| Capacidad mínima de 2MGUI     |  979.0 Kb | 1642.4 Kb |     --     | (5¼) |
| Capacidad límite teórica (82p)| 1001.0 Kb | 1668.2 Kb |     --     |      |
+-------------------------------+-----------+-----------+------------+------+
| Récord absoluto previo a 2M   |  984.0 Kb | 1722.0 Kb | 2880.0 Kb  |      |
| Capacidad máxima 2M (2MF /M)  | 1066.0 Kb | 1886.0 Kb | 3772.0 Kb* |  3.5 |
| Capacidad mínima de 2MGUI     | 1178.3 Kb | 1974.5 Kb | 3949.0 Kb* | (3½) |
| Capacidad límite teórica (82p)| 1201.2 Kb | 2002.0 Kb | 4003.9 Kb  |      |
+-------------------------------+-----------+-----------+------------+------+
   (*) No probado. En esta lista están recogidos sólo los formatos soportados
       por prácticamente todas las unidades y en casi todos los ordenadores. 

     Hay también otro pequeño problema técnico: si la capacidad de la pista es múltiplo del tamaño de sector lógico empleado (aunque ese sector sea de 128 bytes en lugar de 512) se derrocha espacio al redondear hacia abajo. La tentación era fuerte: permitir que un sector lógico pueda estar entre dos pistas. De esta manera, la capacidad total de un disco no puede ser múltiplo entero del número de pistas y cabezales. Solución: crear un controlador de dispositivo que trate al disco como un array de sectores (un dispositivo con un sector por pista, un cabezal, y muchísimas pistas, igual que un disco virtual). Así, por ejemplo, los discos de 3½-HD con 12329 bytes por pista tienen en total (con las 82 pistas habituales) 2.021.956 bytes (que equivalen a 15.796 sectores de 128 bytes, totalizando 2.021.888 bytes con un desperdicio de sólo 68). Utilizando una sola FAT, un número razonable de entradas al directorio y clusters de 2048 bytes (que en las pruebas han demostrado generar discos notablemente más rápidos que los de 512 bytes) el espacio disponible para el usuario (visible con DIR) alcanza los 2.015.232 bytes netos (1968K). Se trata de nuevo de 1968K... pero esta vez no son brutos, sino netos, y además en todas las unidades (y no en casi ninguna).

     En escritura, estos discos son 2 ó 3 veces más lentos que en lectura, aproximadamente. En lectura son sin embargo algo más rápidos que los discos estándar optimizados. La lentitud escribiendo es obvia: imaginemos que hay que escribir un sector ubicado entre dos pistas: primero habra que leer una pista, modificar algunos bytes finales y volverla a escribir, luego leer la siguiente para cambiar unos bytes al principio y escribirla de nuevo...¡todo eso para cambiar un sector lógico de 128 bytes!. Sin embargo, tampoco es para tanto, ya que por lo general el DOS envía bloques grandes a los dispositivos y esto supone la escritura directa e inmediata de las pistas completas... que además utilizan la técnica de Sector Sliding (la posición inicial del sector-pista está desplazada según la ubicación en el disco). De hecho, cacheando las áreas del sistema, la velocidad de escritura seria probablemente muy superior, al agilizar el cuello de botella que supone el acceso a la FAT. Sin embargo, el consumo de memoria del programa (unos 17 Kb) ya es respetable sin caché, y no se llega tampoco al extremo del viejo 1968 de reservar 240 Kb de XMS.

     El programa (un único fichero EXE que se carga en el CONFIG.SYS y luego se puede ejecutar desde la línea de comandos para formatear) es totalmente flexible tanto a nivel lógico (posibilidad de reprogramar el tamaño de cluster, el número de entradas al directorio y el número de FATs) como físico (posibilidad de elegir número de pistas, densidades, Sector Sliding X e Y (expresado además en grados angulares) e incluso un parámetro nada menos que para indicar los bytes por pista (por si el usuario tiene una unidad que admite más). Dispone también de una opción para medir con precisión la velocidad de rotación de la unidad y para calcular qué capacidad máxima soporta. La flexibilidad de un disco virtual... pero en un disquete; el número de formatos es prácticamente infinito, según la voluntad del usuario. Una de las opciones es formatear las 28 pistas más externas en alta densidad y las 54 restantes en doble, en un disco de 360K, obteniéndose 1.2M bastante más fiables de lo que se podría esperar.

+---------------------------------------------------+
| C:\AUXI>2mgui                                     |
|                                                   |
| 2MGUI instalado en memoria.                       |
|   - Nueva unidad E: 1.2M (unidad física A:)       |
|   - Nueva unidad F: 1.44M (unidad física B:)      |
|     Ejecute 2MGUI /? si desea obtener ayuda.      |
|                                                   |
|                                                   |
| C:\AUXI>dir e:                                    |
|                                                   |
|  Volume in drive E is unlabeled                   |
| File not found "E:\*.*"                           |
|            0 bytes in 0 file(s)                   |
|      997.376 bytes free                           |
|                                                   |
| C:\AUXI>chkdsk e:                                 |
|                                                   |
|       997.376 bytes total disk space              |
|       997.376 bytes available on disk             |
|                                                   |
|         2.048 bytes in each allocation unit       |
|           487 total allocation units on disk      |
|           487 available allocation units on disk  |
|                                                   |
|       655.360 total bytes memory                  |
|       649.776 bytes free                          |
|                                                   |
|                                                   |
| C:\AUXI>dir f:                                    |
|                                                   |
|  Volume in drive F is unlabeled                   |
| File not found "F:\*.*"                           |
|            0 bytes in 0 file(s)                   |
|    2.015.232 bytes free                           |
|                                                   |
| C:\AUXI>chkdsk f:                                 |
|                                                   |
|     2.015.232 bytes total disk space              |
|     2.015.232 bytes available on disk             |
|                                                   |
|         2.048 bytes in each allocation unit       |
|           984 total allocation units on disk      |
|           984 available allocation units on disk  |
|                                                   |
|       655.360 total bytes memory                  |
|       649.776 bytes free                          |
|                                                   |
| C:\AUXI>_                                         |
+---------------------------------------------------+
                EJEMPLOS DE ACCESO A UN DISCO DE 360K
                Y OTRO DE 1.44M FORMATEADOS CON 2MGUI

     Con QEMM, si se instala el driver en memoria superior hay que indicar DMA=13 (unidades 1.44M) ó DMA=25 (unidades 2.88M) en las opciones del controlador de memoria, ya que el buffer para acceso directo a memoria que establece por defecto es de sólo 12 Kbytes (EMM386 establece 32 Kb).

     Las nuevas letras de unidad 2MGUI también soportan discos estándar e incluso 2M (teniendo instalado también 2M). De hecho, estas nuevas unidades posibilitan el empleo de discos 2M en OS/2.

12.6.7.10 - USO DE 2M 3.0 EN OS/2 2.1

     Veamos qué consideraciones hay que tener en cuenta para utilizar disquetes 2M en OS/2. Para empezar, es necesario arrancar el DOS desde un disquete o desde un fichero imagen de disco, ya que en las ventanas DOS ordinarias 2M no puede controlar los accesos a disco. Curiosamente, sí se puede formatear en estas ventanas, pero no trabajar con el disco: lo que sucede es que el sistema de ficheros de la emulación DOS que incorpora OS/2 está gestionado al parecer sin llamadas a la BIOS, precisamente las que intercepta 2M, que por tanto no se da cuenta de los accesos a disco. Una vez arrancado desde un fichero imagen con, por ejemplo, MS-DOS 6 (creado con el VMDISK del OS/2) 2M funcionaría perfectamente. Pero lo más probable es que el usuario tenga instalada la utilidad FSFILTER.SYS para poder acceder a las particiones HPFS y, sobre todo, para poder escribir sobre las particiones FAT ordinarias, que serían de sólo lectura en caso contrario. Y aquí vuelven los problemas: al instalar este driver que altera la INT 21h, 2M deja de nuevo de funcionar.

     La solución más rápida consiste en crear un driver que implemente 2 nuevas unidades lógicas (como la D: y la E: por ejemplo) que utilicen la BIOS para acceder a disco: en estas nuevas unidades ya no habrá problemas para trabajar con los disquetes 2M. Este driver sería un programa enteramente DOS, que sin embargo no se puede instalar en las ventanas DOS normales de OS/2, ya que en ellas están prohibidos los dispositivos de bloque. Por tanto, su utilización queda restringida a las ventanas de DOS que incorporen una auténtica versión de este sistema (obtenidas con VMDISK sobre un disquete de arranque, a menos que el usuario desee arrancarlas desde disquete cada vez que vaya a emplearlas).

     Pese a la solución de dicho driver (en nuestro caso 2MGUI), existe algún problema relativamente importante que comentar. El más interesante consiste en que OS/2 comprueba periódicamente si ha habido un cambio de disco en alguna unidad, accediendo a la misma en ese caso para comprobar su contenido -con independencia de que el usuario esté haciendo otra cosa en ese momento, como jugar a los marcianitos mientras espera los resultados de un programa de cálculo-. Si no hay disco introducido no sucede nada, pero si lo hay y es de tipo 2M, OS/2 se queda intentando leerlo de manera obsesiva hasta el punto de colapsar la ventana DOS, que queda literalmente colgada (aunque no el resto de las ventanas ni el sistema en conjunto). La solución, si se estaba trabajando en esta ventana, es retirar el disquete de la unidad y esperar un segundo o dos. Ah, y no volver a introducirlo hasta que no se vaya a utilizar, para evitar nuevas molestias. Por fortuna, OS/2 suele tener cuidado de no fisgar por las disqueteras cuando están siendo usadas. La solución ideal sería un driver que integrara en OS/2 el soporte de estos disquetes, pero eso requiere saber construir controladores para OS/2.

     Las primeras versiones de 2M venían acompañadas de un driver DOS que realizaba la tarea descrita; sin embargo, desde 2M 1.3+ fue sustituido incorrectamente por una recomendación al usuario acerca de la instalación de DRIVER.SYS, programa que no llama a la BIOS (sino al propio DOS; por tanto, con efectos nulos). Por consiguiente, con 2M 3.0+ aparece de nuevo soporte oficial para este sistema.

Volver al Índice