Ficheros de acceso directo con Microdrives Esta es mi traduccion al castellano del primero de una serie de articulos publicados originalmente en italiano por la revista Sinclair Computer: " Probando y comprobando, dos colaboradores han descubierto como hacer cosas curiosas con los microdrives. Acceso directo con Microdrives Por R. Zonin y D. Bolla Los Microdrives representan una notable mejora respecto al cassette de audio normal. Ya sea en terminos de velocidad como fiabilidad. Pero, al ser tambien un dispositivo de cinta, mantiene uno de los principales defectos del cassette: la imposibilidad de acceder en modo RANDOM (aleatorio) a los datos. Vamos a ver mas adelante que si hay un modo de implementar acceso RANDOM, pero antes, tratemos la parte teorica. Acceso secuencial y acceso directo. En un dispositivo de acceso secuencial no es posible acceder directamente a cualquier dato memorizado en un fichero en el que se deben leer antes todos los datos que las preceden. El acceso sera siempre leyendo el primer registro, luego el segundo, y asi hasta llegar al registro que nos interesa. Es evidente que este modo de buscar los datos es muy lento. Un tipico dispositivo de acceso secuencial es la cinta de cassette. El acceso secuencial es, en cierto modo, fisicamente propio de las cintas. Los dispositivos de acceso random (aleatorio) permiten leer directamente los datos que nos interesan, pues se saltan todos aquellos que los preceden. De esta forma la busqueda es mas rapida y flexible, pero la gestion se vuelve un poco mas compleja. Los dispositivos de acceso random mas difundidos son los floppy disk. Las unidades de disco son mucho mas costusas, y dificilmente al alcance del bolsillo del usuario medio del Spectrum. A los los fans de Sinclair que quieran probar las tecnicas de acceso aleatorio o directo en este sistema, les proponemos un metodo para tratar este tipo de acceso en el Microdrive. El Microdrive El soporte sobre el cual el microdrive registra los datos, es un cartucho de cinta que presenta dos diferencias que son sustanciales respecto al cassette de audio. La primera es que la cinta esta constituida por un anillo que continua girando delante del cabezal de lectura, como en los viejos cassettes stereo (alguno lo recuerda?). La segunda diferencia fundamental es que el cartucho del microdrive se tiene que formatear. Eso significa que, antes de poder guardar algun dato, el cartucho ha sido dividido en varias zonas, llamadas sectores. En cada sector se ha almacenado un numero progresivo, que lo identifica univocamente, eso es una serie de informacion de control. Cada uno de estos sectores esta destinado a contener un registro de datos, el cual a su vez sera numerado para hacerlo reconocible univocamente dentro de un fichero. El truco es... A este punto debemos ser claros de que una vez anotada la posicion de un dato dentro de un fichero, nada impide que calculemos en que registro el dato esta. Y una vez que la posicion logica del dato dentro del fichero es descubierta (osea el numero del registro) en el Spectrum y en grado de encontrar la posicion fisica en el cartucho (eso es el numero del sector). Todo lo que debemos hacer para acceder directamente a nuestros datos es "hacerle creer" al sistema que ha leido ya todos los datos precedentes, Como todos los "hackers" ya saben, estamos por ir a curiosear en las variables del sistema. Donde meter las manos... Las variables que nos lnteresan no son las variables del sistema mismo, sino la informacion que se crea solo cuando es usado el microdrive. Esta se encuentra en un area llamada Canales del microdrive, que generalmente comienza a partir de la direccion 23844, dentro del area llamada informacion de los canales, apuntada por la variable CHANS. En cuanto a la que guarda la lectura de datos, son 2 las variables que nos interesan: CHREC (23857): indica el numero progresivo del registro apenas leido dentro del fichero, en el rango 0 - 255 (un fichero es de un largo de unos 128 kb maximo; al menos en teoria, porque en la practica los cartuchos no contienen mas de 100 Kbytes). CHBYTE (23855/23856): apunta al proximo caracter a leer en el registro: la lectura del microdrive es de hecho por bloques de 512 bytes, que son memorizados en un buffer de RAM. Estas variables indican en que punto estamos con la lectura dentro del registro. Ahora que hacer... Esta claro ahora que para encontrar un pequeño dato basta con conocer su posicion dentro del fichero (comprendida como la distancia del primer caracter). Ya, ahora diran, pero la posicion... como la encontramos? Existen varias formas, y todo segun como se han memorizado los datos. Supongamos por ejemplo que almacenamos datos de longitud variable. En este caso la unica posibilidad es la de guardar en una tabla el punto inicial de cada dato, y usar esa tabla para la busqueda. El listado 1 nos muestra un simple ejemplo de este metodo. Naturalmente esta no es la solucion mas optima, sobe todo porque obliga a tener en memoria una tabla de informacion incomoda y encima inutil, en cuanto carece de datos que sean significativos para nosotros (en un archivo de direcciones son significativos "apellido" y "telefono", pero no la "posicion ocupada en el fichero"). El unico modo de eliminar esta tabla es hacer estandar la longitud de cada dato. Manteniendo fija esta longitud dentro del fichero, es mucho mas facil calcular la posicion de la informacion que nos interesa. Por ejemplo, en un archivo de direcciones donde cada dato es de 80 caracteres, la 12ava direccion comienza en el (80*12=) 960avo caracter. Podemos ver un ejemplo de este metodo en el listado 2. Ahora me diras, es simple encontrar un dato conociendo su numero de orden. Y este numero como lo encuentro? No puedo buscar el telefono del señor 15 o la de la señorita 61? Muy bien, para eso necesitamos algo que lea el dato que estamos buscando por su numero de orden, que a su vez nos de su posicion en el fichero. Osea, ecesitamos de una clave. La clave Antes de ver que cosa se entiende por clave, examinemos con mas detalle el metodo de busqueda en el fichero que queremos crear. Supongamos, de tener nuestro archivo de direeciones, que ahora queremos imprimir los datos de nuestro amico Pinco Pallino. A la pregunta del computador "registro a imprimir?", tipeamos "Pinco Pallino". Ahora el computador se pondra a buscar el numero correspondiente a Pinco Pallino, leera los datos memorizados en el microdrive y los imprimira. El campo usado por la maquina para hacer la busqueda es lo que llamamos campo clave (o simplemente clave), y es lo que nos brinda acceso a un grupo de datos (por ejemplo, una direccion). Noten que la clave de acceso al dato es parte del dato mismo. En particular, esta es la parte a denotar, asi en una agenda de direcciones, la clave puede ser el apellido y el nomre, en un catalogo de discos seria el titulo del long play; es importante de todos modos que la clave aluda unicamente al dato al cual queremos referirnos. La parte del dato elegida como clave sera cargada en memoria antes de hacer la busqueda, que al efectuarse en RAM es mas rapido que en microdrive; una vez ubicado, se carga del drive la parte restante. Volviendo al ejemplo anterior, el programa carga en RAM todos los nombres y apellidos contenidos en el fichero, poniendolos en una matriz; asi que examinara la matriz, hara la busqueda del nombre que le dimos para que lo encuentre, y una vez localizado, se multiplicara su posicion por el numero de caracteres ocupado de cada direccion y asi tendremos la posicion de la direccion completa del fichero. Con esta informacion, el programa carga del microdrive el resto del registro: calle, ciudad, telefono, etc. el listado 3 muestra un ejemplo de este modo de operar. Una ultima observacion: con este metodo podemos seguir las busquedas en un fichero mediante el campo clave elegido pero si usamos como clave el nombre y el apellido, no nos permite buscar ya sea ciudad o calle. En seguida veremos como superar esta limitacion con el uso de claves multiples. Comentarios: Como ya vimos, existen dos modos de registrar los datos: uno que utiliza matrices para saber donde se halla el dato y el otro que utiliza registros de longitud fija y que por ello ya no requiere de dichas tablas. El metodo de matrices (listado n.1) tiene la ventaja de que los datos ocupan solo el espacio necesario y ni un byte mas; de este modo los datos pueden tener cualquier longitud sin problemas. La desventaja es la de tener en memoria una tabla de tamaño notable; pero la modificacion de ficheros con este tipo de sistema resulta posible solo si se poseen dos micro drives. El metodo de longitud fija (listado n.2) es estandar, no es tan dificil de implementar, no ocupa memoria con matrices extrañas, y puede ser usado con un solo microdrive. Su lado negayivo es que la longitud de los datos debe ser definida y los espacios no aprovechados son escritos en el microdriva junto con los que se utilizan; esto provoca un desperdicio de la memoria del cartucho. Como el Spectrum gestiona los datos Por datos no entendemos aqui solo los relativos a una base de datos, sino a cualquier clase de informacion que se desee almacenar (programas, pantallas, c. maquina, etc.). Vamos a ver la figura 1. Un sector esta constituido por un bloque de cabecera que contiene el numero de sector y el nombre del cartucho; tras una zona libre tenemos el bloque de datos, que contiene un descriptor de registro, en el cual esta escrito el numero del registro, su longitud, el nombre del fichero al cual se refieren dichos datos; tambien hay un byte de control que sirve al computador para saber si los datos que ha cargado son los correctos. Le siguoen los datos que nos interesan. En la figura 2 se puede observar como el Spectrum, cuando memoriza programas, no utiliza sectores contiguos; generalmente escribe un sector si y otro no. Eso hace que los datos se distribuyan mas uniformemente dentro de la cinta. Gracias a este truco el tiempo medio de acceso es de cerca de 4 segundos y el tiempo de carga de los bloques no es muy largo sino casi instantaneo; esto hace a los microdrive menos lentos de lo que algunos quieren creer. En el manejo de los cartuchos, debemos tener cierto cuidado: no se debe apagar con un cartucho insertado y por sobre todo nunca quitar o poner un periferico con el computador encendido a menos que queramos matar todo el equipo. Un floppy-disk es mucho mas delicado que un cartucho. Si bien cualquier problema puede surgir (como fallos de fabricacion) por lo que una vez formateado, el cartucho nos ofrece una capacidad realmente baja (menos de 48K). Claro que esto se puede remediar, simplemente formateando mas veces (hasta 15 o 20) el cartucho mismo: veremos que los "K" se habran recuperado. No tengamos temor de continuar formateando, hasta que consigamos un resultado satisfactorio (verificable con CAT). " Glosario REGISTRO: debemos distinguir entre el registro fisico y el registro logico. Por registro fisico entendemos un bloque de 512 bytes de datos, mas una serie de informacion de control, que es transferido a o desde el microdrive en una sola operacion de lectura o escritura. Es sinonimo de bloque de datos. Por registro logico en cambio entendemos un grupo de datos que se refieren al mismo objeto. Por ejemplo, en una agenda telefonica, el registro logico de cada persona contiene nombre, apellido, prefijo, numero telefonico; un archivo de libros contendra titulo, autor, año, casa editorial. CAMPO: por campo de un registro se entiende uno de los datos que el registro puede contener; por ejemplo, el campo ciudad, el campo titulo, etc. Con frecuencia campo tambien indica el espacio fisico donde se puede escribir un dato. Si por ejemplo decidimos que el campo ciudad sea de 10 car., e insertamos "Milano", quedara registrado de todos modos un grupo de 10 car., aun si el dato es de solo 6. DATO: tiene un significado mucho mas vasto; nosotros lo usaremos para indicar el contenido de un registro logico o de un campo de registro, asi que un dato puede ser la direccion de una persona, el titulo de un libro, etc. FICHERO: por fichero entendemos una coleccion de registros. La maquina lo ve como una serie de registros fisicos (bloques); nosotros en cambio lo vemos como una serie de registros logicos (datos). BLOQUE DE DATOS: el bloque minimo que nuestro Spectrum puede leer o escribir es de hasta 512 bytes. Notese que, mientras nosotros podemos crear registros grandes cuantos queramos, el Spectrum carga y salva solo 512 bytes por vez. FORMATEO: una operacion durante la cual el Spectrum busca los bloques defectuosos dentro del cartucho y los marca de modo que ya no se usen. La capacidad teorica posible de un cartucho es de 130560 bytes, pero desafortunadamente no se pueden usar sino cerca de 93000. Como utilizar los programas Informacion general: Estos programmi contienen la estructure base de la busqueda random de modo que pueden ser usados por muchos que tengan un minimo de conocimiento de la interface 1. Recordemos que los ficheros abiertos por los tres programas tienen el mismo nombre (que puede ser cambiado segun guste, y que uno recuerde cuando efectue su busqueda); ademas los tres ficheros generados son generalmente incompatibles entre si. Lo que es mas, vemos que para mejor utilizar un programa muy simplificado, procuramos que el canal de datos abierto fuese solo uno, esto es lo uico que nos interesa; enseguida vemos que se pueden gestionar mas ficheros a la vez. No se preocupen si por ahora no se puede modificar el fichero creado, ya lo hemos pensado y lo veremos en un proximo numero por ahora solo queremos que comprendan como funcionan los tres istados. Listado n.1 Para poder ejecutar el listado 1, debemos insertar un cartucho formateado en la unidad 1 y tipear GOTO 35. El programa nos pedira que ingresemos los datos... tipeamos un numero tal que el microdrive arranque al menos una vez. No se preocupen si deben digitar mucho, ya que esta version salva todo lo que digitemos debido a que el buffer de canales es de 512 bytes... En cuanto terminemos damos GOTO 1000 y el computsdor nos pedira un numero de registro. Digitenlo (no pongan numeros extraños) y el computador nos mostrara el contenido de ese registro. Para poder volver a leer los datos despues de ingresarlos, o tras haber apagado el computador, debemos salvar antes el programa sin dar CLEAR, y ejecutarlo mediante GOTO 1000 (para asi salvar tambien la matriz). Listado n.2 El listado 2 se lanza con RUN. Los datos ingresados no deben superar los 20 caracteres, a diferencia del listado anterior en el cual cada campo podia tener cualquier longitud. Cuando se ha terminado, se hace un RUN 1000, notese que no hay mas variables extrañas para salvar, en este punto se nos pedira el nro. de registro que queramos ver y entonc es nos lo mostrara en pantalla. Listado n. 3 El listado 3, aparte de ser mas completo, hace que la longitud del campo no este mas limitada a 20 caracteres. Encima, es posibile modlflçar los parametros. Si arrancamos con RUN entonces podemos escoger entre varias opciones. La opcion 3 debe ser utilizada solo cuando se ha comprendido bien para que cosa sirven las variables. Debemos elegir primero la opcion 1: si el computador no encuentra un fichero con el mismo nombre, entonces se prepara para el ingreso de los datos. Noten que si se escriben mas caracteres de los consentidos, estos seran brutalmente truncados. Una vez terminado, se escoge la opcion 2, digitamos el apellido a buscar en el registro, y entonces veremos todos los datos del registro completo. Programas Microdrive 5 REM listado n.1 10 REM DEFINICION DE LAS VARIABLES Y CADENAS BASE 11 REM DIM P(1000) := MATRIZ QUE TIENE LA POSICION RELATIVA DEL DATO 12 REM DIN :=DATOS INSERTADOS 13 REM IRD :=DIRECCION RELATIVA DEL DATO ACTUAL 21 LET Z$="NOMBRE ": RETURN 22 LET Z$="APELLIDO ": RETURN 23 LET Z$="TELEFONO ": RETURN 24 LET Z$="CIUDAD ": RETURN 25 LET Z$="ZONA ": RETURN 26 LET Z$="FECHA DE NACIM. ": RETURN 27 LET Z$="PROFESION ": RETURN 28 LET Z$="INTERESES ": RETURN 29 LET Z$="NOTAS VARIAS ": RETURN 30 LET Z$="VARIOS ": RETURN 35 CLEAR #: DIM P(1000): LET DIN=1: LET IRD=0: LET P(1000) =IRD 40 OPEN #10;"M";1;"IND.1" 41 REM $$$$$$$$$$$$$$$$$$$$$$$ 50 REM RUTINA DE INSERCION DE DATOS 60 FOR C=1 TO 10 70 GOSUB(20+C): INPUT (Z$),D$:PRINT Z$;D$: GOSUB 8050 80 NEXT C 150 INPUT "QUIERE INSERTAR MAS DATOS? s/n ";I$: IF I$="s" THEN GOTO 60 160 CLOSE #10: STOP 999 REM $$$$$$$$$$$$$$$$$$$$$$$ 1000 REM RUTINA DE IMPRESION DE DATOS 1005 OPEN #10;"M";1;"IND.1" 1010 INPUT "CUAL REGISTRO IMPRIMO ? ";S 1012 CLS 1015 FOR C=1 TO 10 1020 LET D=(S*10)+C: GO SUB 8000: INPUT #10;D$ 1030 GOSUB 20+C: PRINT Z$;D$ 1040 NEXT C 1060 INPUT "QUIERE CONTINUAR? s/n ";I$: IF I$="s" THEN GO TO 1010 1070 STOP 7998 REM $$$$$$$$$$$$$$$$$$$$$$$ 7999 REM SUBRUTINA DE MODIFICAR VARIABLES DE SISTEMA PARA LA BUSQUEDA RANDOM 8000 LET PR=P(D): LET PA=PR-512*INT (PR/512): LET R=INT (PR/512) 8005 LET k=PEEK 23857: POKE 23911,0 8010 IF k<>R THEN POKE 23855,0: POKE 23856,2: POKE 23857, R-1: INPUT #10;S$ 8020 POKE 23855,(PA-256*INT (PA/256)): POKE 23856,INT (PA/256):RETURN 8050 REM $$$$$$$$$$$$$$$$$$$$$$$ 8051 REM SUBRUTINA DE IMPRESION DEL FICHERO 8060 LET LD=(LEN D$)+1: LET IRD=IRD+LD: LET DIN=DIN+1 8070 LET P(DIN)=IRD: PRINT #10;D$: RETURN 5 REM LISTADO N.2 10 REM DEFINICION DE LAS VARIABLES Y CADENAS BASE 12 REM DIN :=DATOS INSERTADOS 20 LET A$=" ":GOTO 40 21 LET Z$="NOMBRE ": RETURN 22 LET Z$="APELLIDO ": RETURN 23 LET Z$="TELEFONO ": RETURN 24 LET Z$="CIUDAD ": RETURN 25 LET Z$="ZONA ": RETURN 26 LET Z$="FECHA DE NACIM. ": RETURN 27 LET Z$="PROFESION ": RETURN 28 LET Z$="INTERESES ": RETURN 29 LET Z$="NOTAS VARIAS ": RETURN 30 LET Z$="VARIOS ": RETURN 40 CLEAR #: OPEN #10;"M";1;"IND.1" 41 REM &&&&&&&&&&&&&&&&&&&&&&& 50 REM RUTINA DE INSERCION DE DATOS 60 FOR C=1 TO 10 70 GO SUB 20+C: INPUT (Z$),D$ 72 LET D$=D$+A$(1 TO 20-LEN D$) 74 PRINT Z$;D$: PRINT #10;D$ 80 NEXT C 150 INPUT "QUIERE INSERTAR MAS DATOS? s/n ";I$: IF I$="s" THEN GO TO 60 160 CLOSE #10: STOP 999 REM &&&&&&&&&&&&&&&&&&&&&&& 1000 REM RUTINA DE IMPRESION DE DATOS 1005 CLOSE #10: OPEN #10;"M";1;"IND.1" 1010 INPUT "CUAL REGISTRO IMPRIMO ? ";S 1012 CLS 1015 FOR C=1 TO 10 1020 LET D=(S*10)+C-1: GO SUB 8000: INPUT #10;D$ 1030 GOSUB 20+C: PRINT Z$;D$ 1040 NEXT C 1060 INPUT "QUIERE CONTINUAR? s/n ";I$: IF I$="s" THEN GO TO 1010 1070 STOP 7998 REM &&&&&&&&&&&&&&&&&&&&&&& 7999 REM SUBRUTINA DE MODIFICAR VARIABLES DE SISTEMA PARA LA BUSQUEDA RANDOM 8000 LET PR=D*21: LET PA=PR-512*INT (PR/512): LET R=INT (PR/512) 8005 LET k=PEEK 23857: POKE 23911,0 8010 IF k<>R THEN POKE 23855,0:POKE 23856,2: POKE 23857,R-1: INPUT #10;S$ 8020 POKE 23855,(PA-256*INT (PA/256)): POKE 23856,INT (PA/256):RETURN 3 REM LISTADO N.3 6 REM DEFINICION DE LAS VARIABLES Y CADENAS BASE 7 LET LC=20: REM LONG.CAMPO 8 LET NC=10: REM NUM.CAMPOS 9 LET NR=100: REM NUM.REG. 10 GO SUB 9000 15 GOTO 4000 21 LET Z$="APELLIDO ": RETURN 22 LET Z$="NOMBRE ": RETURN 23 LET Z$="TELEFONO ": RETURN 24 LET Z$="CIUDAD ": RETURN 25 LET Z$="ZONA ": RETURN 26 LET Z$="FECHA DE NACIM. ": RETURN 27 LET Z$="PROFESION ": RETURN 28 LET Z$="INTERESES ": RETURN 29 LET Z$="NOTAS VARIAS ": RETURN 30 LET Z$="VARIOS ": RETURN 40 CLOSE #10: OPEN #10;"M";1;"IND.1" 41 REM *********************** 50 REM RUTINA DE INSERCION DE DATOS 60 FOR C=1 TO NC 70 GO SUB 20+C: INPUT (Z$),D$ 72 LET D$=D$+A$(1 TO LC-LEN D$) 73 LET D$=D$(1 TO LC) 74 PRINT Z$;D$: PRINT #10;D$ 80 NEXT C 150 INPUT "QUIERE INSERTAR MAS DATOS? S/n ";I$: IF I$="s" THEN GO TO 60 160 PRINT #10;CHR$ 27;CHR$ 27;CHR$ 27: CLOSE #10: RETURN 999 REM *********************** 1000 REM RUTINA DE IMPRESION DE DATOS 1005 CLOSE #10: OPEN #10;"M";1;"IND.1" 1010 INPUT "CUAL REGISTRO IMPRIMO ? ";S 1012 CLS 1015 FOR C=1 TO NC 1020 LET D=(S*NC)+C-1: GO SUB 8000: INPUT #10;D$ 1025 IF CODE D$=27 THEN PRINT "Final del fichero": GO TO 1060 1030 GOSUB 20+C: PRINT Z$;D$ 1 040 NEXT C 1060 INPUT "QUIERE CONTINUAR ? s/n ";I$: IF I$="s" THEN GO TO 1010 1070 CLOSE #10: GOTO 4000 2000 REM *********************** 2001 REM BUSQUEDA RND CON CLAVE 2010 INPUT "NOMBRE DEL FICHERO ?";N$ 2020 OPEN #10;"M";1;N$: DIM R$(NR,LC) 2030 FOR J=1 TO NR: LET D=(J-1)*NC 2040 GOSUB 8000: INPUT #10;R$(J): REM CARGO LA CLAVE 2045 IF CODE R$(J)=27 THEN LET J=NR+1 2050 NEXT J 2100 INPUT "APELLIDO ?";K$ 2200 LET J=1 2210 IF K$=R$(J,1 TO LEN K$) THEN GOSUB 3000: GOTO 2240: REM ENCONTRADO 2220 IF JR THEN POKE 23855,0: POKE 23856,2: POKE 23857,R-1: INPUT #10;S$ 8020 POKE 23855,PA-256*INT (PA/256): POKE 23856,INT (PA/256): RETURN 9000 LET S$="": LET A$="": FOR J=1 TO LC: LET A$=A$+" ": NEXT J: RETURN Y hasta aqui el articulo completo excepto las ilustraciones de las figuras 1 y 2 que acompañaban al texto. (c)2022 zx_if1@hotmail.com