UNA MANZANA DENTRO DEL ESPECTRO DE LUZ o del Basic (Entero) de Apple-1 al Basic Sinclair A modo de introducción. Nunca pensé que mi afición por el ZX Spectrum (que empezó allá por 1984 cuando compré un "gomas") me llevaría a interesarme por otro aparato aun más antiguo: el APPLE-1. Y todo por un programita para Spectrum, precisamente un emulador de Apple-1 para nuestro querido ZX. Hace años que lo descargué de internet y lo probé, sólo que no pasé del "prompt" y no supe qué más hacer, así que lo dejé hasta que lo retomé recientemente y empecé a buscar más información para poderla usar. Y aquí están los resultados de mis investigaciones. Pero, ¿qué sabemos del APPLE-1? Pues, que fue inventada por Steve Wozniak allá por el año 1976, lo que la hace la primera auténtica computadora personal tal cual la conocemos hoy en día. Por solamente $666.66 uno obtenía una simple "placa madre" (la mayoría de aparatos de ese entonces se solía vender como kits para armar) con 4k de RAM. Aparte se compraba el teclado, la pantalla y la interface para grabadoras de cinta, así como una expansión de RAM de 4k, la cual era necesaria para el BASIC. ¡Ah... y dos fuentes de poder por lo que he entendido! En cuanto al "case" había que tener imaginación. Algunos lo hacían de madera, otros usaban un maletín para meterlo todo ahí, así que no hubo un Apple-1 igual en diseño externo, pues era al gusto del usuario, prevaleciendo el de madera. Barata, barata, que digamos, no era, pero pegó en su momento e inició el boom. Encima, al encenderla, uno se daba con un prompt indicando que la cosa esperaba a que uno tipeara algo, solo para descubrir que no tenía Basic. El Apple-1 empieza en modo monitor hexadecimal y había que cargar el BASIC de una cinta de cassette, la cual venía de "regalo" si uno compraba la dichosa interface de cinta de grabar. Y aparte los 4k extras para el Basic, que era mapeado a la dirección &E. Sin eso no hay Basic, ni modo de salvar o cargar nada. ¡La alternativa era ponerse a tipear el listado hexadecimal del BASIC cada vez que uno prendiese la máquina! Una vez armado y encendido el aparato, tras verificar que todo está OK, sólo queda cargar el Basic de la cinta. Para ello hay que: 1. tipear C100R y ENTER 2. luego E000.EFFFR y pulsar PLAY en la grabadora 3. pulsar recién ENTER y esperar que cargue el Basic 4. en 30 segundos debe aparecer un "\" en pantalla y listo, a programar. La pantalla del Apple-1 tiene 40 columnas por 24 líneas de texto, sin ningún modo de alta o baja resolución gráfica ni sonido. Carece de editor de textos, por lo que el cursor baja a medida que uno tipea y pulsa ENTER. Le sucedió el APPLE ][, con una versión ampliada del Basic original al cual llamaron "Integer Basic", ya que la versión original era llamada simplemente "Apple Basic", y el resto es historia. Apple es la única que ha sobrevivido hasta el día de hoy, desde sus inicios a diferencia de todos sus competidores como Commodore, Atari o Sinclair. Terminada la introducción pasamos a hablar... Parte I SOBRE EL EMULADOR Apple 1 Emulador para Sinclair ZX Spectrum, por Thomas Goering Version 1.0 (06/01/2007) Este es un port del emulador de Simon Owen (para SAM Coupe) del Apple 1 para el Sinclair ZX Spectrum. Probado en varios emuladores para Windows y Mac, menos en un real ZX Spectrum, tanto 48k como 128k. El emulador requiere de al menos 48k de RAM. Su binario ha sido ensamblado con la versión de ROM de Ken Wessen, la cual incluye el ensamblador Krusader (v. 1.2), el monitor y basic del Apple 1. Permite la opción de ingresar textos como si hubiesen sido tipeados igual que el emulador para SAM. Esta opción debe funcionar con emuladores del Spectrum, ya que el texto debe ser importado a la RAM, direccion &B800 (47104) con un largo máximo de &0800 (2048). El texto debe encontrarse de acuerdo con el modo correcto, es decir si se está en Monitor, cargará todo ahí desde la pos. cero. Si se está en Basic cargará el listado o ejecutará los comandos que encuentre. Igual con el ensmablador Krusader. Tras cargar el programa, empezamos en modo monitor y los listados están en codigo hexadecinal. Desde este modo pasamos al Basic tipeando E000R. Para acceder al emsamblador Krusader debemos tipear F000R y podremos entonces trabajar con listados en ensamblador 6502. Hay dos versiones en TZX del emulador. La versión 1 ofrece 16k y la opción de importar textos, además de hard reset. El hard reset inicializa toda la memoria del Apple 1 (ROM y RAM). Esto es necesario ya que la opción de textos limita la memoria a 16k, para evitar que suceda la sobreescritura en la memoria. La versión 2 ofrece 32k, nada de importar textos ni hard reset. Teclas epeciales: CAPS SHIFT + SYMBOL SHIFT = ESC CAPS SHIFT + SPACE = Soft Reset CAPS SHIFT + ENTER = Hard Reset (solo versión 1 with 16K RAM) Hasta ahí la traducción del texto original en inglés del autor. Ahora vamos a probar el programa y como acceder al Basic Entero de Apple 1. Para empezar, veamos el programa que consta de un cargador llamado "loader" y una rutina en C.M. llamada "appleones". El cargador es el mismo para los dos: 10 CLEAR 26879 20 POKE 23610,255 30 LOAD "" CODE 40 RANDOMIZE USR 26880 Ambas versiones empiezan en 26880, pero difieren en longitud: la versión de 16k tiene 13832 de largo, y la de 32k es de 13576 en comparación. Una vez cargado el programa aparece una pantalla inicial con letras blancas sobre fondo negro y tras pulsar una tecla, se limpia la pantalla quedando en verde sobre negro y se nos muestra lo sigte: \ @ indicando que está en modo monitor y espera que el usuario tipee algo. Para acceder al Basic desde este pto., basta con tipear E000R y enseguida ENTER, entonces vemos a continuación: E000: 4C >@ indicando que ahora ya podemos empezar a tipear comandos o sentencias Basic. Para salir del Basic y volver al monitor basta con pulsar el botón RESET que en el caso del Spectrum es practicamente BREAK. Y para retornar al Basic sin borrar el listado previamente en memoria hay que tipear E2B3R y listo. En suma, cada vez que uno salga del Basic por "x" motivos, no puede volver con E000, ya que este inicializa el Basic, borrando cuanto se haya tipeado antes. En cambio, E2B3 retorna al Basic, reteniendo el programa en curso. Y ahora continuamos con... Parte II BASIC (ENTERO) DE APPLE 1 Palabras reservadas: Auto, Clr, Del, List, Run, Scr, Himen, Lomen, Let, Input, Print, Tab, For, To, Next, Step, If, Then, Goto, Gosub, Return, Dim, Rem, End, Poke, Call, Not, And, Or, Mod, Abs, Sgn, Peek, Rnd, Len Abreviaciones usadas en este texto: exp - expresión aritmética var - nombre de variable val - un número entre -32767 y 32767 inclusive. <~ - representa la tecla ENTER Creado por el mismo Steve Wozniak para su Apple 1. Originalmente él lo llamó Apple Basic. No sería sino hasta que él y Steve Jobs hicieron el Apple ][ que ellos lo renombraron como "Integer Basic" para Apple ][, además de añadirle nuevas instrucciones que en su versión original no estaban implementadas. Las instrucciones Basic se dividen en comandos y sentencias. Comandos Se ejecutan inmediatamente de pulsar <~. Los sigtes. comandos de control son usador para ingresar, examinar, modificar o ejecutar los programas BASIC. AUTO val {,val2} Automáticamente nos da los números de línea para hacer el programa. Siendo val la línea inicial y val2 su incremento. Si se la omite será 10 por defecto. Sin parámetros devuelve error. CLR pone a cero todas las variables, cancela cualquier FOR o GOSUB pendiente, así como toda matriz o cadena. DEL val {,val2} elimina las líneas del programa desde val a val2. Si se omite val2, solamente se borra la línea val. LIST [val {,val2}] lista el programa desde val hasta val2. si omite val2, solo mostrará la línea val. Sin parámetros lista todo el programa. RUN {val} hace un CLR y ejecuta el programa desde la línea val. Sin parámetros ejecuta todo el programa desde su línea inicial. SCR destruye el programa existente en memoria con todo y variables. No queda nada. HIMEM= exp al usarse destruye cualquier programa existente y fija el límite de la memoria alta según la exp dada en decimal (inicialmente 4096). LOMEM= exp igual que HIMEM pero para la memoria baja (inicialmente 2048) Sentencias solamente pueden ser usadas tras un número de línea dentro de un listado de BASIC. INPUT item donde: item = un texto opcional, var, var$ o matriz var() una sentencia INPUT puede tener varios items separados por una coma. INPUT imprime un signo "?" indicando que espera a que el usuario ingrese algo. Si hubiera varias respuestas, estas se tipearan una seguida de otra separadas por comas, o pulsando <~ tras cada respta. Si fueran variables de cadena entonces usar <~ por cada una en vez de comas. Ejemplos: INPUT A INPUT A,B,C$,D(2) INPUT "ENTER A, A$ ,8(3)", A,A$,B(3) FOR var = expl TO exp2 {STEP exp3} NEXT var donde: var = indice o contador del bucle exp1 = valor inicial exp2 = límite exp3 = incremento opcional La sentencia FOR inicializa var y comprueba que termine el bucle. Next incrementa el contador de 1 en 1 a menos que se use Step para cambiar eso. GOSUB exp RETURN donde: exp = una constante, variable o cálculo numérico Gosub salta a una subrutina en la línea indicada por exp. Return debe estar al final de la subrutina para indicar el retorno al punto desde el que se la llamó. Sentencias comandos son las que pueden usarse tanto tipeandolas directamente como dentro de listados Basic. {LET} var = exp evalúa la expresión y la asigna a una variable ya sea numérica, de cadena o matriz. PRINT item(s) La inversa de INPUT, imprime en la pantalla cualquier item que se le dé. TAB exp imprime n espacios, de acuerdo con exp. ejemplos: TAB 20: PRINT "Hello" PRINT A;:TAB 20:PRINT B IF (expr) THEN st / val donde: st = una sentencia BASIC val = un número de línea válido Salta a un número de línea (como GOTO) o ejecuta una instrucción dependiendo de que exp sea cierta o falsa. Sólo puede ser usada como comando directo si a THEN le sigue un comando. Ejemplos: IF A=B THEN C=l IF (A=B AND C=D) THEN 50 IF NOT (A>4) THEN END GOTO exp salta a una línea del listado de acuerdo con el valor de exp. DIM var (exp) {,var2 (exp2) , ...} dimensiona una matriz numérica o una cadena. Una vez hecho eso, ya no hay redimensionamiento. REM {txt} permite añadir mensajes txt a un programa sin afectar su ejecución. END termina la ejecución de un programa. Su omisión genera error. POKE expl, exp2 donde: exp1 = un valor entero y exp2 = un valor de 0 a 255 coloca en la posición de memoria exp1 el valor exp2. ejemplo: POKE 4,64 POKE -2048,55 pone 55 en la posición -2048 (&D000 en hex) CALL exp llama a una subrutina en codigo máquina alojada en posición de memoria exp. Funciones el Basic de Apple-1 solamente tiene unas pocas funciones que son: ABS(exp) - da el valor absoluto de la expresión SGN(exp) - devuelve -1 si exp = negativo, 1 si exp = positivo , 0 si exp = cero PEEK(exp) - lee la posición de memoria exp y da un valor entre 0 y 255 RND(exp) - devuelve entero aleatorio entre 0 y exp-1, si exp = positivo y da entre 0 y exp+1, si exp = negativo LEN(var$) - devuelve el número de caracteres de la cadena var$ exp1 MOD exp2 - da el resto entero de una división entera Expresiones El Basic devuelve uno (1) si se cumple la condición (verdadero), cero (0) si no (falso). exp = exp2 1 si ambas expresiones son iguales exp > exp2 1 si exp es mayor que exp 2. exp < exp2 1 si exp es menor que exp 2. exp >= exp2 1 si exp es mayor igual que exp 2. exp <= exp2 1 si exp es menor igual que exp 2. exp <> exp2 1 si ambas expresiones son distintas. exp # exp2 1 como la condición <>. exp AND exp2 1 si ninguna exp es igual a cero. exp OR exp2 1 a menos que ambas exp sean iguales a cero, -exp valor negativo de exp. NOT exp 0 si exp es no-cero, 1 si es cero. Manejo de cadenas y matrices MATRICES Apple-1 solo acepta un unico tipo de matriz, las listas o vectores, es decir, de una sola dimensión. Intentar con más de una dimensión genera error. Se pueden crear tantas matrices con n subindices, como permita le memoria que tengamos disponible. De suceder generará error. El primer elemento de una matriz es igual a una variable simple. Poe ejemplo: tipear B es igual a tipear B(1). No hay subindice cero y tampoco puede ser negativo. Genera error de intentarse. El contenido de toda variable no definida, o matriz recien creada es cero. CADENAS Apple-1 solo permite trabajar con cadenas, si estas son primero creadas con DIM y la longitud máxima no puede pasar de 255. Si no se la define, entonces su longitud es de 0, y solo admite un caracter o la cadena nula. Mientras que PRINT A=0 es valido, PRINT C$="1" no lo es. En el caso de cadenas deben usarse parentesis. Así que PRINT (C$="1") sí es aceptado. SUBCADENAS Veamos pues como el Apple-1 maneja las cadenas y genera subcadenas. tomaremos los ejemplos del manual, haciendo DIM A$(7) y asumiremos que A$="ABCDEFG", entonces PRINT A$ = ABCDEFG PRINT A$(5) = EFG - imprime la cadena a partir del subindice 5 PRINT A$(2,6) = BCDEF - parte de la cadena dentro del rango dado PRINT A$(l,l) = A - el mismo subindice da el caracter de esa posición Una cadena o parte de ella puede ser copiada o pasada a otra cadena. Si no se especifica ningún subindice, toda la cadena es copiada como en el ejemplo: A$=B$. Si la cadena a copiar es más corta que la cadena de destino, entonces se completa con espacios en blanco. En el caso A$(5)=B$, esta última reemplazará lo que haya a partir del subindice 5 en adelante. No es permitido hacer A$(3,5)=B$, pero si A$(3)=B$(1,3). Tampoco es permitido concatenar cadenas sumandolas: C$=A$+B$ da error. Si hacemos DIM B$(20) y luego PRINT LEN(B$) obtendremos cero. Pero B$="ALFA" nos da LEN = 4. Esto significa que LEN puede ser usada para fusionar cadenas del modo sigte.: B$ (LEN(B$)+1) = A$. Esto es, siempre que B$ tenga espacio suficiente para sumarle todo A$. La sentencia IF acepta cadenas como expresiones, pero solo admite los signos de comparación "=" y "#", por "igual a" y "distinto de". Las cadenas comparadas tambien pueden tener subindices como por ejemplo: IF A$(3,7)=B$(4,8) THEN ... . Mensajes de error del Basic de Apple *** SYNTAX - error sintactico o de tipeo *** >32767 ERR - número menor de -32767 o mayor de 32767 *** >255 ERR - fuera del rango de 0 a 255 *** BAD BRANCH ERR - intento de ir a número de línea inexistente *** BAD RETURN ERR - hay más RETURNs que los GOSUBs correspondientes *** BAD NEXT ERR - se hizo un NEXT sin su FOR correspondiente *** >8 GOSUBS ERR - más de 8 GOSUBs anidados *** >8 FORS ERR - más de 8 FOR-NEXT anidados *** END ERR - el programa termina sin END *** MEM FULL ERR - se excedió el tamaño de la memoria permitida *** TOO LONG ERR - demasiados paréntesis anidados *** DIM ERR - se da cuando e intenta dimensionar una cadena ya dimensionada *** RANGE ERR - el índice de una matriz o cadena es mayor al rango o menor de 1 *** STR OVFL ERR - número de caracteres mayor al valor de la cadena en DIM *** STRING ERR - intento de hacer una operación de cadena ilegal RETYPE LINE - solicita que se corrija un valor erroneo de variable INPUT STOPPED AT - dice en qué linea se interrumpió un programa para poderlo proseguir. EL MONITOR Tiene solo 4 instrucciones básicas que son: DM donde DM = dirección de memoria en hexadecimal. Tras pulsar <~, vemos el contenido de dicha dirección. DM1 . DM2 donde dm1 y dm2 = direcciones de memoria inicial y final. lista el contenido de dicho bloque de memoria. [DM] : h1 h2 h3 ... donde DM = dirección inicial opcional, pues ":" usa la dirección por defecto. h = lista de valores hexadecimales que se guardarán a partir de DM. [DM] R ejecuta la rutina almacenada a partir de DM o la dirección por defecto. Con la interface de casete, tenemos una nueva instrucción: D1.D2 W donde d1.d2 = bloque de memoria a salvar en cinta por W(rite) mientras que para cargar se hace lo mismo pero reemplazando W por R. Hasta aquí lo que nos dice el manual, pasamos luego a lo que el manual no nos dice y es... INSTRUCCIONES NO IMPLEMENTADAS Las sigtes. son instrucciones llamadas "fantasmas", pues no figuran en el manual, pero están ahí en la memoria como parte del sistema base. OFF es un comando sin parámetroas. Al ingresarla no parece pasar nada, pero tras tipear algo a continuación, el sistema parece congelarse y no hay forma de salir de esto, hasta que uno pulsa RESET. USR(exp) esta es la función que complementa a CALL. Y de hecho sí "funciona", llama a cualquier rutina en código máquina como CALL. Ejemplo: 10 PRINT USR(99) COLOR= exp No hace nada. Su presencia indica los planes de Wozniak de añadirle color a su APPLE a futuro. PLOT exp1,exp2 Tampoco hace nada. Simplemente nos dice de los planes del autor de dotar al APPLE de futura resolución gráfica. HLIN exp1,exp2 AT exp3 Tampoco funciona. Su función sería en el APPLE ][, para dibujar una línea en la horizontal. Curiosamente falta su complemento VLIN AT. RNDX una función, totalmente desconocida en cuanto a uso y sintaxis y por ende, no hay como hacer que el Basic la admita. Parte III I - SAVE/LOAD en el Apple-1 El manual enseña como salvar y cargar un programa con la configuración estandar de 8k del Apple-1, donde LOMEM = &800 y HIMEM = &1000. Para cargar o grabar un programa en el equipo original se debe salir del BASIC y ejecutar la rutina contenida en la PROM del interface de cassette. Para cargar desde cinta: Tipear C100R y pulsar <~. Tipear 004A.00FFR 0800.0FFFR, pulsar “PLAY” en el casete y pulsar <~. Esto carga dos rangos de datos. Uno es la cabecera y el otro el programa con todo y variables. Para grabar en cinta: tipear C100R seguido de <~. tipear 004A.00FFW 0800.0FFFW, pulsar “REC” en el casete y enseguida <~. El programa se salva de tal modo que la proxima vez ya no es necesario cargar primero el Basic. Basta encender el aparato y cargar el programa que uno salvó antes y pasar al Basic con E2B3R y listo. El programa esta ahí. II -SAVE/LOAD en el Apple-1 emulado II.1 En un Spectrum real El autor dice no haber probado su emulador en un Spectrum real, pero si los diversos emuladores de Spectrum replican la cosa real lo más cercano al 90%, entonces supongo que debería funcionar sin mayores problemas de compatibilidad. Así que... pasamos los TZX a cintas físicas o a discos de Opus, +D, Beta128, Microdrive, o Wafadrive y lo cargamos en un 48k o 128k y si todo sale bien, ya solo nos queda un problema, como salvar o cargar programas. El emulador no parece haber replicado el interface de casete redirigido al sistema de casete del Spectrum y menos aun, instrucciones para pasarlo a un sistema de discos. Entonces... una alternativa es usar multiface-1 para salvar un programa Apple-1, ya sea a cinta, microdrive, opus, o wafadrive. Beta128 y el +D poseen su propio botón mágico para salvar snapshots. Y al +3 le bastaría el multiface-3. Habría que probar si esta teoría funciona en la practica. II.2 Un emulador ejecutando otro emulador En este caso tenemos dos modos de hacerlo. El primero es el mismo que antes mencionamos respecto al Spectrum real. El segundo consiste en la opción del emulador de importar textos directamente de un fichero de texto a la memoria del Apple-1 y entonces aplicar el metodo del multiface para pasar los programas a un sistema de disco para Spectrum. Empiezo como siempre con REALS en modo 128k, cargo la versión 1, la de 16k y paso de frente al BASIC. Todo OK. Regreso al MONITOR y a ver qué puedo hacer. Encuentro en internet la sigte. rutina "hello world" y la tipeo: 0000: A9 8D 20 EF FF A9 00 BD 0008: 16 00 D0 03 4C 1F FF 20 0010: EF FF E8 4C 07 00 48 45 0018: 4C 4C 4F 20 57 4F 52 4C 0020: 44 21 00 0R 0000: A9 HELLO WORLD! Muy bien, a continuación la pruebo en SPECTACULATOR y también en EMUZWIN 27. Aquí aprovecho para usar el debugger, para ver dónde realmente se almacena la rutina y obtengo: 49152 = C000 - posicion de codigos del monitor inicio 0000 La rutina E000 del Basic es justamente 57344. Sabiendo esto, regreso al REALS y busco la opción ALT-F9 para salvar un bloque de memoria. Tipeo 49152 y 23 y lo salvo con nombre "apple1hello2.bin". Aparte, con Klive creo un SNA 128k, el cual carga sin problemas en REALS, zx32, Spectaculator, FUSE, SpecEmu, EmuZwin, z80s, X128W, WinZ80 y Zesarux. El fichero BIN creado por REALS lo pruebo con EIGHTYONE, SpecEmu, FUSE, x128w, Spin y Zesarux. Spectaculator puede leer ficheros BIN pero no hay opción de crearlos, a diferencia de los otros ya mencionados. Lo extraño es que a veces la rutina se corrompe y en vez de "hello world", obtengo un error, además de que se alteran los datos tan solo ejecutar con R. En el Apple-1 las variables del BASIC se guardan a partir de la posición &0800 (2048) que en el Spectrum equivale a &C800 (51200) Perfecto, ya sabemos como salvar y cargar ficheros binarios de Apple-1 y con qué emuladores, aparte de los típicos SNA o Z80. Ahora pasamos a probar con el modo de salvar los listados Basic. Aunque la rutina de la grabadora del Apple-1, no ha sido incluida, los datos empiezan en &800 y terminan en &FFF, eso es 51200 y 53247 en el Spectrum. La cabecera empieza en 4A y acaba en FF, o sea 49226 y 49407. En suma, para salvar el programa Basic de tan solo 2k, debo salvar a partir de 49226 hasta 53247, lo que nos da una longitud de 4021. Para cargarlo se da el valor inicial ya dicho, el Apple-1 debe estar reseteado en modo monitor, sólo entonces cargamos el fichero y tipeamos E2B3R y listo. Una vez en Basic, el programa debería estar presente. Debe seguirse este procedmiento para que cargue correctamente, si se hiciera estando ya en Basic, simplemente no reconoce el programa cargado. Tipeo el sigte. listado para probar: 5 REM DEMO1 10 FOR I=1 TO 10 20 PRINT"*"; 30 NEXT I 40 PRINT"FIN" 50 END Busco en el emulador la opción "salvar bloque de memoria", doy el valor inicial y su longitud, a continuación el nombre de fichero y listo. Muy bien, el fichero binario ha sido creado con REALS y paso a ver que lo cargue y ejecute Spectaculator, x128w, FUSE, SpecEmu, EightyOne y Zesarux. Sigo los pasos: 1. Apple-1 en modo monitor 2. busco opción "cargar bloque de memoria", valor inicial (y el largo si pide) 3. cargo el fichero binario y tipeo E2B3R para ir al Basic. (a veces genera un error pero basta con RESET y reintentarlo para que funcione) 4. de frente RUN para ejecutar el programa - no hay problema hasta aquí. Pero: 5. hago LIST y entonces el sistema se cuelga al llegar a la última línea 6. salgo pulsando RESET y vuelvo a entrar al Basic con E2B3R 7. vuelvo a tipear la última línea y listo. El programa ya puede listarse sin provocar cuelgue. Vuelvo a revisar y resulta que no salvé con la longitud correcta para que cargue bien más tarde. Eso era todo. Una vez corregido eso, ya no hay más problemas al listar. Ya está. Ya sé cómo salvar y recuperar programitas BASIC de cerca de 2k. Ahora hay que ver como se hace con programas de mayor tamaño. Para tipear un listado de más de 2k hay que cambiar el LOMEM (la memoria baja) a 768 por ejemplo, tipear el listado y buscar las posiciones correspondientes tanto de la inicial como su longitud para salvar el programa completo de modo que sea exitoso. III - LA OTRA VERSION - con 32k Muy bien, paso ahora a probar la otra versión, la que no tiene importación de textos a la dirección 47104, ni hard reset. Y los resultados fueron... Intento cargar los ficheros creados con la verión 1, siguiendo los pasos antes mencionados, pero nada de nada. No aparece listado alguno. Ni en hexadecimal, ni en Basic. La única conclusión es que todas las posiciones usadas para salvar y cargar los datos que descubrí en la versión 1 están cambiadas de lugar. Pruebo a tipear la rutina "hola mundo" a partir de cero y obtengo error. Así que elijo el punto &1000 para retipear todo. Al final yo no obtengo más que nada, el dichoso mensaje nunca se produce, pero ya no hay error. No importa dónde coloque la rutina, no se ejecuta a diferencia de la versión de 16k. El monitor permite ingresar datos y listarlos pero no ejecutarlos. Utilizo el "debugger" de EmuZwin y obtengo finalmente la posición, que en este caso equivale a 32768. Cargo la rutina que creé usando la versión 16k, ejecuto, ¡et voila! Finalmente aparece el mensaje deseado y sin errores. Vuelvo a salvar el fichero, vuelvo a cargarlo y con exito. Ahora, digamos que por alguna razón, no se carga el fichero completo, entonces basta con tipear lo que falta para que se ejecute tal como uno espera que lo haga. En cambio, cada vez que tipeo algo desde cero, en la versión 32k, la rutina no se ejecuta, nada más lo hace cuando cargo una rutina previamente creada con la versión 16k, y sólo así todo funciona. El por qué de este comportamiento no lo sé. Tal vez un "bug" en el emulador. Así que tiro la toalla respecto al Monitor y paso a ver el Basic. El ingreso al Basic es normal. Ahora tengo que ver en qué posición de la RAM del Spectrum se almacena la información que quiero cargar o salvar. Vuelvo a buscar en el "debugger" y logro encontrar la parte donde empieza la cabecera y resulta ser 32843, mientras el listado empieza al parecer en 33269. Sigo los pasos que apliqué en la versión 16k para cargar y finalmente funciona. Pongo a continuación una comparación de posiciones de memoria entre la versión emulada con sus respectivas posiciones en el Spectrum según la versión 16k o la 32k: MAPA DE MEMORIA DEL APPLE 1 Apple-1 versión 16k versión 32K pag.cero &0000 =&C000 (49152) =&8000 (32768) buffr tecl. &0200 (512) =&C200 RAM sist. 4k &0280 (640) =&C280 (49792) =&8280 (32843) &0800 (2048) =&C800 (51200) &0FFF (4095) =&CFFF RAM sist. 8k &1000 (4096) =&D000 (53248) &1FFF área Basic &E000 (57344) ens. Krusader &F000 (61440) área monitor &FF00 Y pára cerrar este tema del SAVE/LOAD... Como sea, ahora tenemos dos opciones, por un lado tipear programas a la antigua, tal como se hacía entonces, usando el emulador de APPLE-1 y salvando los datos como snapshots y la otra es simplemente convertir los programas al BASIC de Sinclair, con lo que podemos hacerles las mejoras pertinentes a los listados, evitandonos así, las limitaciones del caso. Eso es en el caso de los listados Basic de Apple-1, pero en el caso de sus datos binarios, para no tener que tipear tantos valores hexadecimales, entonces podemos aplicar el sigte. truco (siempre que se pueda)... Tomemos por ejemplo, un programa de ajedréz para el Apple-1, descargamos el fichero "ASMmchess.txt", al abrirlo nos encontramos con que empieza así: 0300: A2 58 BD .... .... mediante NOTEPAD eliminamos las direcciones y los ":", dejando nada más los valores hexadecimales. Ahora debemos editarlo hasta que quede como un bloque de texto continuo y entonces lo salvamos. Seleccionamos todo, lo copiamos y abrimos un programa editor hexadecimal gratuito como el XVI32. Creamos uno nuevo y buscamos la opción CLIPBOARD del menú EDITAR. Escogemos la opción "pegar de una cadena hexadecimal". Un a vez hecho eso, salvamos todo como fichero binario, con un nombre como "a1chess.bin". De aquí, vamos al emulador como REALS, cargamos el fichero bin como bloque en la dirección 0300, es decir, la C300 (49920) del Spectrum. Finalmente tipeamos 0300R y listo, veremos ejecutarse el programa. Un emulador que si ofrece la opción "paste" (pegar) es MESS, lo cual significa que podemos seleccionar todo un listado como texto, lo copiamos y pegamos. Pero no parece permitir salvar un SNA, para su uso con otros emuladores, como es el caso de REALS. Lo cual significa que no podemos pasar los datos de MESS a REALS por ejemplo. Otro emulador que ofrece la opción pegar es SPECEMU, mediante ALT-P, pero sólo funciona con el editor del 128k. No funciona con el 48k ni cuando otro programa se ejecuta. Por lo tanto no permite copiar textos al emulador APPLE-1. Ahora que ya sabemos como salvar y cargar los datos como ficheros binarios en un emulador, proseguimos con... Parte IV COMPARANDO BASICS Exceptuando AUTO, DEL, HIMEM, LOMEM y CALL, todos los comandos BASIC del APPLE-1 existen o tienen su equivalente en el Basic Sinclair; lo cual lo convierte en un subset del Basic del Spectrum. En cuanto a las dos primeras, basta con una extensión como "xbasic", "extended basic" o "betabasic". Como el Spectrum, Apple-1 usa 1 para cierto y 0 para falso. Así como tener varias instrucciones en una misma línea separados por el signo ":". GOTO y GOSUB del Apple-1 operan igual que sus equivalentes del Basic de Atari y Sinclair. Apple-1 usa CLR y SCR en lugar de los más usuales CLEAR y NEW. En cuanto a MOD, basta con una función definida que la replique. Posee la instrucción TAB, pero como sentencia en vez de como orden auxiliar de PRINT. Es decir, mientras en la mayoría de BASICs, el Sinclair incluido, la forma es PRINT TAB 20;"texto", El Basic de Apple usa TAB 20: PRINT "texto". En cambio, carece de cualquier forma de posicionar datos en la pantalla. Eso cambiaría con APPLE ][, cuyo Basic tendría VTAB y HTAB para posicionar y una rutina en C.M. que había que invocar con CALL -936, equivalente a HOME para borrar la pantalla como el más estandar CLS. Para hacer FLASH, INVERSE y NORMAL en Apple ][ hay que POKEar en la dirección 50. Tanto AppleSoft como Sinclair manejan la memoria con el rango de 0 a 65535. Debido a que el Apple-1 trabaja con enteros cortos, mucha gente no sabe como hacer para trabajar con valores mayores a 32767. Con máquinas que usan Basic Entero, hay que usar su correspondiente en negativo, así 32769 es -32767 y 32770 es -32766 y así, sucesivamente hasta llegar a -1 que sería 65535. En ambos BASICs, cada NEXT requiere su variable asociada. Los nombres de variables solo pueden ser una letra sola, ó una letra más un dígito en el caso de variables numéricas y matrices como por ejemplo: A, B1. En el caso de variables alfanuméricas se les añade el signo $ al final, siendo válidas: A$, B$. Solo una letra. En cambio nombres largos como alfa, beta$, c12 ó b1$ son rechazados. Apple-1 y Spectrum comparten el mismo concepto para nombres de cadena, pero el Spectrum puede usar nombres largos para las variables numéricas. De un modo muy similar a Atari, y que es opcional en el Spectrum, el Apple-1 requiere de DIM para inicializar las variables de cadena, de lo contrario, no son reconocidas. En ambos casos DIM crea una cadena fijando la longitud de la misma. La diferencia estriba en que una cadena Apple es iniciada como vacía, en cambio el Spectrum la llena de espacios para completarla. Por lo que si en ambas máquinas hacemos DIM A$(20) y luego LET A$="ABCDEFG", obtendremos lo sigte. APPLE-1 : LEN(A$) = 7 - solo contiene la cadena ingresada SPECTRUM: LEN A$ = 20 - la cadena ingresada + 13 espacios en blanco. En suma, el Spectrum fuerza a crear una rutina o función que omita los espacios en la cadena DIM, para poderla extraer y concatenarla a otra cadena. En cuanto al manejo de subcadenas, veamos los equivalentes Apple-1/Spectrum: APPLE-1 SINCLAIR ZX MICROSOFT A$(5) A$(5 TO) LEFT$(A$,5) A$(1,5) A$(TO 5) RIGHT(A$,5) A$(2,6) A$(2 TO 6) MID$(A$,2,5) A$(l,l) A$(1) MID$(A$,1,1) Además, tiene una similitud exclusiva con el Spectrum 128k de Investronica, que es la de tipear todas las sentencias sin espacios y tras pulsar <~, todo lo tipeado aparece correctamente espaciado. Y por último, mencionar que lo único en común con el ZX-80, es que ambos usan un Basic de tipo entero, en vez de uno de coma flotante. Las instrucciones que uno podría echar de menos: ya que el Monitor opera con valores hexadecimales, mientras el Basic opera con valores enteros decimales cortos, habría sido interesante que hubiese un operador hexadecimal-decimal, como por ejemplo, poder tipear en Basic, algo como &200 o $200, para hacer las conversiones. La otra es posicionado de caracteres en pantalla tipo AT, así como la lectura del teclado tipo INKEY$. Debido a estas limitaciones, no es posible tipear juegos de acción que esperan a que uno pulse una tecla. Pero los juegos de aventura de texto tienen más cabida en máquinas como Apple-1, así como programas que hagan aritmética básica en valores enteros solamente. En suma, un Basic muy simple y limitado. Y tras la comparación, seguimos con... CONCLUSIONES: El Apple-1 original no solo no permite editar una línea, sino que tampoco hay teclas DELETE o SUPRIMIR, ni BACKSPACE para retroceder y corregir algo mal tipeado. O sea que si uno se da cuenta de que ha tipeado mal una línea, no le quedan más que dos opciones: pulsar <~, y ver un mensaje de error como rspta., mientras la otra es pulsar ESC para cancelar lo tipeado y en ambos casos, volver a retipear la línea hasta que todo quede correcto. La máquina original carece de CLS, pero tiene en cambio una tecla que es "CLEAR SCREEN", la cual no ha sido emulada, por lo que no hay manera de limpiar la pantalla y volver a imprimir desde la posición superior izquierda de la misma. Respecto al monitor... es demasiado básico, solo permite ingresr datos, listar y ejecutar. Pero, no mover, copiar o reemplazar en bloques. Por ejemplo, uno esperaría poder hacer algo como: 1000:0.22 - y que esto copiase el bloque 0.22 a la posición 1000, pero no pasa. 0.22:1 - podría esperarse que esto inicialize todo el bloque 0.22 a 1, pero no. Todas esas operaciones hay que hacerlas desde el Basic. En cuanto al "tipeo automático", he probado con la versión de Simon Owen y sí funciona en el SimCoupe. Basta con seguir las instrucciones y resulta... Sí, resulta... que aparece el texto, pero una vez terminado, ya no permanece, así que ya no puede listarse ni ejecutarse. Y respecto a la versión para Spectrum, no he logrado ni siquiera eso. Así que lo dejo ahí. Al igual que el ZX-80 y ZX-81 que vendrían después, el Apple-1 carece de gráficos de alta resolución y de sonido. Al menos las máquinas de Sinclair tienen caracteres gráficos en modo texto. Y nuevamente, al igual que el ZX-80 y 81, el Apple-1 solamente podía salvar las variables junto con el programa entero, pero no separadamente, como es el caso de las matrices DATA en el Spectrum o los ficheros OPEN/CLOSE de la mayoria de BASICs que le sucedieron. Tras llegar a este punto, uno se podría preguntar... ¿para qué un APPLE-1 o incluso emularlo y más aún convertir un Spectrum en un Apple del 76? Diría que la respuesta es solamente una: diversión. Bueno, eso es, si uno encuentra divertido trabajar con una máquina más limitada que el Spectrum. Claro que convertir al Spectrum en un Apple-1, nos permite en cierto modo vivir la experiencia de programar como se hacía a fines de los 70. Era otra cosa, otro mundo. Eran los verdaderos comienzos de lo que hoy vivimos en la era de la informática. Lo que es más, enriquece al Spectrum, en mi opinión, al ofrecer una nueva librería de programas a su disposición, antes impensado. La única cosa que se extraña, es que no se haya emulado la posibilidad de salvar y cargar programas aunque fuese siquiera a cintas. Eso sí que facilitaría un poco más las cosas. Lo único que he omitido en este texto, es lo referente al ensamblador y códigos del 6502, eso ya queda para los que quieran ir más allá del BASIC. (c)2018 zx_if1@hotmail.com