Todo sobre: FICHEROS TIPO PEEK EN EL BETAdisco y Beta128 A modo de introduccion Ficheros, ficheros, ficheros y mas ficheros... ¿Cuantos tipos de ficheros puede manejar el ZX Spectrum? Mientras que la mayoria de BASICs de otros 8bits pueden operar con ficheros de tipo programas, ascii, binarios y tipo OPEN, el Basic Sinclair sin expandir, solamente puede trabajar con ficheros de matrices y de codigo maquina o binarios, asi como programas BASIC tokenizados. Con Microdrives ya puede acceder a ficheros secuenciales. Con sistemas de disco como Opus Discovery o Timex FDD ya se le añaden ficheros de acceso directo. Y por ultimo sistemas de disco como BETA128 o el D80 de Didaktik permiten trabajar con otro tipo de ficheros de acceso directo al disco mismo: los tipo PEEK. ¿Y como son, como se usan o crean? Si buscamos en los manuales originales del TR-DOS para Betadisco, 48, Plus o 128 de Technology Research Ltd., nos encontramos con una breve referencia de que son PEEK y POKE pero en vez de leer solamente la RAM, estos leen sectores del disco mas un simple ejemplo de su uso, dejando al lector usuario a que experimente con ellas y les encuentre un uso. A simple vista pareciera que son unos simples PEEK y POKE que usan el disco como si fuese una RAM virtual, pero son mas que eso, ya que pueden mover datos entre el disco y la RAM del Spectrum. Sin mas info que la de los manuales, ya que no recuerdo ningun magazine o libro que explicase el modo de explotar su potencial real, estas fueron las unicas instrucciones del Betadisco que no me vi animado a probar. Eso es hasta que encontre un manual en italiano de un clon del Betadisco hecho por Sandy, en la seccion Technology Research - Customized Beta Disk ROM y Sandy FDD2 Document de Speccy4ever cuyo enlace es: http://zxspectrum.it.omegahg.com/ En ese manual en su capitulo 5, hay toda la explicacion necesaria para entender y el modo de usar los ficheros de tipo PEEK, el cual he traducido del italiano al español integramente y que ofrezco a continuacion en la parte I. La parte II muestra el listado del programa ejemplo y un apendice trata de su conversion al Beta128 y Didaktik D40/80. Parte I BUSQUEDA ALEATORIA O DIRECTA Antes de entrar en las particularidades de esta nueva posibilidad de tu Spectrum, seria util ver en general, lo que es la busqueda aleatoria (directa) y lo que nos permite hacer. Empezaremos recordando como se organiza el disco, el cual esta dividido en sectores que en el caso de un drive de densidad normal de 40 pistas es 390. Cada uno de estos sectores pueden contener 256 bytes, esto es importante porque si escribimos en un sector 5 o 50 bytes, el DOS no considera siempre 256 y vemos como aprovechar bien eso. En suma el acceso aleatorio es la posibilidad de escribir y leer directamente en uno de 390 sectores del mismo modo como hacemos con la memoria RAM. Es evidente el poder del sistema FDD2, que permite usar el disco como una memoria virtual en la cual se memoriza, durante el funcionamiento de un programma, datos que de lo contrario deberian estar en la RAM. La velocidad de accesso es tal que el programa no lo resiente y la RAM del Spectrum permanece enteramente disponible para el programa y toda rutina que la requiera. Consideremos ahora la organizacion de los datos en el disco. El procedimiento es el de crear datos dentro de sectores que de ahora en adelante llamaremos FILE. Cada sector, que como ya hemos dicho contiene 256 bytes, representa un grupo de datos que pueden tener una organizacion interna. A esos sectores los llamaremos RECORD. Recapitulando: Gran cumulo de sectores ='FILE (fichero) Sectores (2S6 bytes) ='RECORD (registro) Esta estructura adecuadamente organizada puede operar con cualquier tipo de datos. Hagamos un ejemplo: Queremos crear un archivo que contenga los titulos de los libros de nuestra bilblioteca. Este archivo debera almacenar 100 titulos y por cada uno, contener Autor, Casa editorial, Argumentos y toda informacion que consideremos util. Crearemos un FILE de 100 RECORDs (sectores) al que llamaremos "libri". Cada record contendra la informacion antes mencionada. Si no llega a los 256 Bytes podemos agrupar más titulos en un record. Tengamos en mente este ejemplo, porque mas tarde lo aplicaremos. Entraemos ahora en las particularidades de la tecnica de usar nuestro drive para hacer busquedas random, viendo cuales son los trucos para una programacion eficiente. Los comandos del DOS que son para leer y escribir son: PEEK "nombre"CODE bufer de direccion,nro.de sectores POKE "nombre"CODE bufer de direccion,nro.de sectores Recordemos que deben ser precedidas siempre de 'RANDOMIZE USR 15363:REM:' si se usan en programas BASIC. Analicemoslo: nombre Una vez que hemos decidido la cantidad de los datos, debemos crear el fichero que los contenga. Para nuestro fichero debemos salvar al disco una zona de memoria de 100 sectores, 100x256=25600 bytes con el nombre "libri": SAVE "libri" CODE 30000,25600 Ahora nuestro disco ya tiene el fichero "libri" para recibir nuestros datos. Como regla general podemos decir que para crear un fichero, debemos salvar siempre una zona de memoria de igual dimension. El fichero mas grande que podemos realizar seria de 65535 bytes. En caso de necesitar mas espacio ee todavia posible salvar dos ficheros con distinto nombre a los que accedera el programa. bufer de direccion Para que el DOS de nuestra interfaz pueda gestionar aleatoriamente los datos, usa un bufer, es decir una zona de memoria de 256 bytes donde se ponen los datos antes de pasarlos al disco, o donde los carga en la fase de lectura. El dato que ingresamos como bufer es el inicio del area de memoria. Teoricamente el bufer puede ser cualquier zona de la memoria, pero ya que en esos 256 bytes es donde efectuaremos las operaciones, tiene que ser una zona particularmente practica de usar. nro.de sectores Corresponde al sector usado para memorizar el record, o fase de lectura, el sector contiene el registro de lectura. Veamos los ejemplos: POKE "LIBRI" CODE 30000,7 salva en el sector 7 del disco los 256 bytes que son contenidos en la RAM a partir de la locacion 30000. PEEK "libri" CODE 30000,7 lee el registro #7 del fichero "libri" y lo pasa a la RAM a partir de la locacion 30000. Nuestros datos estaran presentes en la 30000 al 30256. Dejaremos en claro ahora algunos puntos que son importantes para crear programas funcionales. Empecemos con las funciones del bufer. Es importante considerar que los datos con los que vamos a trabajar son tratados por la computadora de modos muy variados. De hecho, si vamos a almacenar caracteres, cada byte contendra un codigo ASCII; un record puede contener como maximo 256 caracteres. Usando numeros enteros, nuestro record no contendra 256 si son numeros que pueden ser representados con un byte (de 0 a 255) ni 128 si usamos numeros de 2 bytes (32728 a 65535) o menos aun si son numeros decimales que requieren 5 bytes para la representacion en coma flotante. Para conseguir que los datos en la computadora y el disco se intercambien, deben estar codificados de tal modo con relacion al tipo de datos. En la practica nuestros primeros programas usaran una simple tecnica que deja toda la labor antes mencionada en las manos del DOS y el BASIC Sinclair. El metodo consiste en definir al inicio y exclusivamente al INICIO del programa (lo mas fundamental) una variable de cadena con 256 espacios. Esta cadena sera despues rellenada con datos de cualquier clase, ya sea numeros o palabras, con los que nuestro programa va a operar. Si son numeros ya sabemos que podemos extraer el valor de la cadena, por ejemplo k$="1234" con la funcion VAL: VAL K$=1234. Una vez definida la cadena usaremos como direccion del bufer la direccion del inicio del area de variables + 3. Este 3 depende del modo como el Spectrum memoriza las variables de cadena. De este modo los datos de la computadora estaran siempre dentro de la cadena y se pueden manipular con todas las funciones del BASIC. Veamos un ejemplo: - Definimos la cadena J$="{256 espacios}" - La direccion del area de las variables: adr= PEEK 236Z7+256*PEEK 23628 - Insertamos en la cadena los datos a memorizar - Salvamos dicha cadena J$: RANDOMIZE USR 15363:REM:POKE "Nombre"CODE ADR+3,1 - De este modo hemos salvado en el disco el primer registro del fichero con los datos de la cadena j$. - En cambio para su lectura: RANDOMIZE USR 15363:REM: PEEK "Nombre"CODE ADR+3,1 con eso cargamos la cadena j$ con los 256 bytes del primer registro (recordemos que record = sector) que estaran disponibles como elementos de la cadena. Es importante acordarse de poner en blanco la cadena despues de haberla salvado. Para ello NO se debe hacer una asignacion directa del tipo LET j$="{256 espacios}" como al inicio, sino usar LET j$(1 TO 256)= "{256 espacios}". Eso vale para cualquier asignacion que debamos hacerle a la cadena j$. Ya que si redefinimos directamente la variable que usamos como bufer, su posicion en el area de variables cambiaria y nuestro metodo ya no funcionara mas. Si trabajamos en cambio con datos numericos, debemos de operar de otro modo. Durante la edicion del programma el area de variables se mueve cada vez que se añade una linea; por ese motivo conviene actualizar ADR cada vez que se lee o escribe: LET adr=PEEK(23627+2S6*23528)+3:RANDOMIZE USR l5363: REM:POKE "Nombre" adr,nro. de Sectores ORGANIZACION DE LOS DATOS Retomemos ahora el ejemplo del archivado de libros. Si ya hemos decidido que cada record debe contener: TITULO DEL LIBRO AUTOR CASA EDITORIAL PRINCIPALES ARGUMENTOS TRATADOS Cada una de estas especificaciones sirve de nombre de campo en el record. Nuestro archivo asi estructurado tiene 4 campos. Ya definido esto, debemos establecer cuantos caracteres asignar a cada campo: por ejemplo -TITULO 40 CARACTERES -AUTOR 40 " -CASA EDIT. 70 ” -ARG. TRAT. 100 " TOTAL: 250 CARACTERES Definamos ahora el orden de los campos dentro de la cadena j$ ya inicializada en la primera linea de nuestro programa: J$(1 TO 40) TITULO DEL LIBRO J$(41 TO 80) AUTOR J$(81 TO 150) CASA EDITORIAL J$(152 TO 250) ARGUMENTOS TRATADOS Ya tenemos nuestro record estructurado. Ademas ya nos quedo claro tambien el concepto de campo. Veamos como poner a cero o en blanco nuestra cadena en el caso que debamos usar la funcion VAL. Es todo muy simple: debemos tan solo insertar al inicio de cada campo un cero, ya que la funcion VAL no trata las cadenas vacias. Asi que si nuestros datos fuesen todos numeros con los cuales hacer operaciones, nuestra cadena a definir ha de ser puesta a cero con una mascara similar a la sigte.: LET J$(1 TO 256)="0.......0........0........0....256CAR" cam.1 cam.2 cam.3 cam.4 De este modo la cadena es puesta a cero, en caso de usar VAL con un campo vacio el resultado sera cero, y la posicion de j$ en el area de variables no sufre cambio. Una ultima cosa antes de pasar al listado del programa que crea el archivo de libros. Es necesario que un programa de gestion de ficheros memorice algunos parametros para el fichero mismo, parametros que deben ser leidos y actualizados cada vez que el fichero es usado. Estos datos pueden representar: - resultados de las operaciones con cada record - espacios sobrantes - numero del registro escrito (quizas lo mas importante) Este último nos evita escribir en registros ya usados o perdidas de tiempo leyendo registros vacíos en la fase de búsqueda. Estos parametros son evidentemente memorizados en el file mismo en un registro elegido para ello, ya sea el primero o el ultimo. En la inicializacion de cada nuevo fichero conviene poner a cero el registro con los parametros, usando la mascara adecuada. De hecho una vez creado nuestro fichero puede contener valores importantes de la memoria que podrian causar errores. En cualquier caso lo mejor es controlar que el record no sea accidentalmente puesto en blanco al inicialiar el fichero (ver el listado del programa). Es preciso que en el caso de que los parametros sean muchos (valores totales, parciales etc) y ya que el bufer de la cadena es puesta a cero cada vez, debemos preparar una segunda cadena que ha de ser actualizada de manera continua pero no salvada. Esto sucedera solo al final de las operaciones, inter cambiando el contenido con la variable búfer, ejemplo: - cadena bufer j$ - cadena de los parametros p$ - al final de las operaciones con el file en curso: LET j$(1 TO 256) =p$ (1 TO 256) y salvado con el comando requerido. Una ultima cosa antes de pasar a tipear el listado del programa, debemos acordarnos de crear el fichero "libri" del modo sigte.: SAVE "libri" CODE 30000,25600 B U E N A L A B O R !!! Parte II Ahora que ya sabemos como se crean correctamente los FILE tipo PEEK, pasamos a ver el programa del manual original de la SANDY FDD2, con todos los mensajes traducidos: 10 CLEAR : BORDER 0: PAPER 0: INK 7: CLS 15 REM _inizializzazione 16 REM _variabili 20 LET j$= "{256 espacios}" 22 DIM s$(4,15): LET s$(1)="Titulo": LET s$(2)="Autor" : LET s$(3)="Editorial": LET s$(4)="Arg.Princ." 25 LET ca=1: LET kc=0 26 INPUT "quiere resetear el fichero? s/n ";Z$ 28 IF Z$="s" THEN LET adr=(PEEK 23627+256*PEEK 23628)+3 : RANDOMIZE USR 15363: REM : POKE "libri"CODE adr,100 31 REM _lettura rec.parametri 32 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM :PEEK "libri"CODE adr,100 34 REM _controlla se il file j$ _vuoto CHR 0 o CHR 32 35 IF j$(1)=CHR$ 0 OR j$(1)=" " THEN LET kc=1: GO TO 50 40 LET kc=VAL j$(1 TO 4) 50 CLS : PRINT AT 2,8;"_OPCIONES" 55 PRINT AT 6,8;"1) CREAR FICHERO" 60 PRINT AT 8,8;"2) ACTUALIZAR / INSERTAR" 65 PRINT AT 11,8;"3) BUSCAR REGISTRO" 100 IF INKEY$="1" THEN GO TO 2000 105 IF INKEY$="2" THEN GO TO 4000 110 IF INKEY$<>"3" THEN GO TO 100 1000 CLS : PRINT AT 2,8;"_BUSQUEDA" 1005 PRINT AT 8,8;"1) por Titulo" 1006 PRINT AT 10,8;"2) por Autor" 1007 PRINT AT 12,8;"3) por Editorial" 1008 PRINT AT 14,8;"4) por Argumento" 1009 PRINT AT 16,8;"5) Menu": PAUSE 0 1010 LET t$=INKEY$ 1013 IF t$="5" THEN GO TO 50 1015 IF t$="1" OR t$="2" OR t$="3" OR t$="4" THEN GO TO 1040 1020 GO TO 1010 1040 LET ca=1*(t$="1")+41*(t$="2")+81*(t$="3")+151*(t$="4") 1043 LET t=VAL t$ 1045 INPUT "busqueda por ";(s$(t))' LINE t$ 1049 GO SUB 8000 1090 PRINT AT 19,0;"otra busqueda? s/n" 1100 LET z$=INKEY$ 1105 IF z$="s" THEN GO TO 1000 1110 IF z$="n" THEN GO TO 50 1120 GO TO 1100 2000 LET kc=0: CLS : PRINT AT 2,8;"_INSERTAR REGISTRO" 2010 INPUT "Cuantos reg. insertara? ";rec 2020 FOR i=1 TO rec 2030 GO SUB 9998: CLS : INPUT "Titulo ";j$(1 TO 40) 2035 INPUT "Autor ";j$(41 TO 80) 2040 INPUT "Editorial ";j$(81 TO 150) 2045 INPUT "Principales Arg. tratados"'j$(151 TO 250) 2050 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM : POKE "libri"CODE adr,i 2054 REM _aggiorno rec. parametri 2055 LET kc=kc+1 2060 GO SUB 9998: LET j$(1 TO 4)=STR$ kc 2070 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM : POKE "libri"CODE adr,100 2080 CLS : PRINT AT 10,3;"_registro insertado": PAUSE 50 2090 CLS : NEXT i 2100 GO TO 50 4000 CLS: PRINT AT 2,8;"_ACTUALIZAR FICHERO" 4003 PRINT #0;AT 0,0;"va a insertar un nuevo registro? s/n" 4004 LET z$=INKEY$ 4005 IF z$="s" THEN GO TO 5000 4006 IF z$="n" THEN GO TO 4010 4007 GO TO 4004 4010 PRINT AT 4,8;"Codigo de los campos" 4015 PRINT AT 6,8;"1-> Titulo" 4020 PRINT AT 8,8;"2-> Autor" 4025 PRINT AT 10,8;"3-> Editorial" 4030 PRINT AT 12,8;"4-> Argumentos principales" 4040 INPUT "Titulo del reg. a modificar"'t$ 4045 LET ca=1 4050 GO SUB 9998: GO SUB 8500 4055 INPUT "codigo del campo a modificar ";cc 4060 INPUT (s$(cc));c$ 4065 IF cc=1 THEN LET j$(1 TO 40)=c$ 4070 IF cc=2 THEN LET j$(41 TO 80)=c$ 4075 IF cc=3 THEN LET j$(81 TO 150)=c$ 4080 IF cc=4 THEN LET j$(151 TO 250)=c$ 4085 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM : POKE "libri"CODE adr,mod 4090 PRINT AT 21,0;"campo modificado ": PAUSE 80: PRINT AT 21,0;"t=otro tit. n=otra mod. m=menu" 4095 LET z$=INKEY$ 4100 IF Z$="t" THEN GO TO 4000 4110 IF z$="n" THEN GO TO 4055 4115 IF z$="m" THEN GO TO 50 4120 GO SUB 4095 5000 GO SUB 9998: CLS : INPUT "Titulo ";j$(1 TO 40) 5010 INPUT "Editorial ";j$(81 TO 150) 5045 INPUT "Principales Arg. tratados"'j$(151 TO 250) 5050 INPUT "Autor ";j$(41 TO 80) 5060 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM : POKE "libri"CODE adr,kc 5100 LET kc=kc+1: GO SUB 9998: LET j$(1 TO 4)=STR$ kc 5110 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM : POKE "libri"CODE adr,100 5200 GO TO 4090 6000 REM _STAMPA RECORD 6005 CLS : PRINT "REGISTRO nro. ";mod: PRINT 6010 PRINT PAPER 1; BRIGHT 1;s$(1); PAPER 0; BRIGHT 0' j$(1 TO 32)' 6015 PRINT ' PAPER 1; BRIGHT 1;s$(2); PAPER 0; BRIGHT 0' j$(41 TO 72)' 6020 PRINT ' PAPER 1; BRIGHT 1;s$(3); PAPER 0; BRIGHT 0' j$(81 TO 112)' 6025 PRINT ' PAPER 1; BRIGHT 1;s$(4); PAPER 0; BRIGHT 0' j$(151 TO 250)' 6030 PRINT AT 17,0; FLASH 1;"SPACE"; FLASH 0;" interrumpe busqueda de: ";s$(t) 6031 PRINT AT 2*(ca=1)+5*(ca=41)+8*(ca=81)+11*(ca=151),0; FLASH 1;s$(1*(ca=1)+2*(ca=41)+3*(ca=81)+4*(ca=151)) 6034 PRINT AT 21,0; FLASH 1;"ENTER"; FLASH 0;" para continuar" 6035 LET z$=INKEY$ 6040 IF CODE INKEY$=32 THEN GO TO 1090 6045 IF z$="" THEN GO TO 6035 6100 RETURN 8000 REM _routine di ricerca 8010 FOR i=1 TO kc 8020 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM :PEEK "libri"CODE adr,i 8030 IF t$=j$(ca TO ca+LEN t$-1) THEN LET mod=i: GO SUB 6000 8040 NEXT i: CLS : BEEP 0.1,16: PRINT AT 10,8;"_Fin de la busqueda": PAUSE 80: GO TO 50 8500 FOR i=1 TO kc 8510 LET adr=(PEEK 23627+256*PEEK 23628)+3: RANDOMIZE USR 15363: REM :PEEK "libri"CODE adr,i 8530 IF t$=j$(ca TO ca+LEN t$-1) THEN LET mod=i: RETURN 8540 NEXT i: CLS : BEEP 0.1,16: PRINT AT 10,8;"_Fin de busqueda": PAUSE 80: GO TO 50 9998 LET j$(1 TO 256)= "{256 espacios}" 9999 RETURN A modo de apendice... CONVIRTIENDOLO A BETA128 Como se ve, el programa ejemplo "libri" fue pensado para la FDD2 de Sandy que era un clonico del primer Betadisk, el cual carecia de ficheros tipo OPEN/CLOSE, por lo que estos ficheros PEEK eran su unica alternativa. A partir del Beta 48 y Beta Plus, el TRDOS ya incluye la posibilidad de trabajar con ficheros tipo OPEN, asi que el Beta128 tampoco requería mucho de los ficheros tipo PEEK, pero aun retiene dichos comandos. La conversión es mucho más sencilla, solo hay que cambiar todos los USR 15363 por USR 15619 y listo, cualquiera de los programas que usen PEEK en el Betadisk correran o deberian correr sin problemas en el Beta128. Y para finalizar... Sandy tambien ofrecia en 1984 un FDD2 con un sistema op. llamado SP-DOS, el cual usaba el comando PUT en lugar de POKE y GET en vez de PEEK. DIDAKTIK 80 Finalmente llegamos al Didaktik D40/80, el cual también permite manejar y crear ficheros tipo PEEK. Su M-DOS usa las instrucciones READ* y RESTORE* en lugar de PEEK y POKE respectivamente. La sintaxis de READ* es: READ* "drive/volumen:[nombre]",sector,dirección. RESTORE* comparte la misma sintaxis que READ*. El unico detalle es que aqui se trabaja con sectores de 512 bytes del disco, en vez de los 256 del Beta. Si cada sector equivale a un registro, como en el caso del Betadisco, ahora tenemos el doble de caracteres a manejar por registro. Eso significa que para que el programa de Sandy funcione correctamente en el D80 hay que hacer lo sigte: 21 LET j$=j$+j$ 28 IF z$="y" THEN LET adr=(PEEK 23627+256*PEEK 23628)+3 : RESTORE* "libri",1,adr 32 LET adr=(PEEK 23627+256*PEEK 23628)+3: READ* "libri", 1,adr 2050 LET adr=(PEEK 23627+256*PEEK 23628)+3: RESTORE* "libri",i+1,adr 2070 LET adr=(PEEK 23627+256*PEEK 23628)+3: RESTORE* "libri",1,adr 4085 LET adr=(PEEK 23627+256*PEEK 23628)+3: RESTORE* "libri",1+mod,adr 5060 LET adr=(PEEK 23627+256*PEEK 23628)+3:RESTORE* "libri",1+kc,adr 5110 LET adr=(PEEK 23627+256*PEEK 23628)+3: RESTORE* "libri",1,adr 8020 LET adr=(PEEK 23627+256*PEEK 23628)+3: READ* "libri", i+1,adr 8510 LET adr=(PEEK 23627+256*PEEK 23628)+3: READ* "libri", i+1,adr 9999 LET j$(1 TO 512)=j$+j$:RETURN Por ultimo, acordarnos de crear el fichero "libri" del modo sigte.: SAVE* "libri" CODE 30000,25600 Para tener los 100 registros necesitariamos hacer: SAVE* "libri" CODE 0,51200 Y eso es todo. Tomando en cuenta que el MDOS del D80 solo trabaja con ficheros secuenciales de tipo OPEN, este es al parecer, el unico metodo en el Didaktik para crear los ficheros de acceso directo, con ficheros tipo PEEK a disco. Nota: Mientras en el Betadisco, 25600 nos permite trabajar hasta con 100 registros, sin podernos pasar de 256 caracteres, aqui solamente podemos trabajar con la mitad, osea casi 50 registros. Los otros 256 quedan sobrantes y sin utilizarse, lo que es un desperdicio de espacio a menos que uno sepa como explotar eso a futuro. Al menos nos da una idea de como usar READ* y RESTORE* para crear ficheros tipo PEEK en un Didaktik. Y con algo de imaginacion ya encontraremos el modo de aprovechar todos los 512 espacios por sector. (c)2021 zx_if1@hotmail.com