Mapping the Atari - Revised Edition, por Ian Chadwick
PRÓLOGO
Traducción al español del libro Mapping The Atari - Revised Edition de Ian Chadwick publicado por COMPUTE! Books en 1985.
Traducción y página web preparada por Luis Baeza en Mayo de 2025.
Favor enviar sus comentarios, correcciones y felicitaciones a lbaeza at yahoo dot com.
PÁGINA LEGAL
MAPPING THE ATARI
Edición Revisada
Ian Chadwick
Introducción de Bill Wilkinson
COMPUTE! Publications, Inc.
Parte de ABC Consumer Magazines, Inc.
Una de las compañías editoriales de ABC
Greensboro, Carolina del Norte
Edición revisada: derechos de autor de 1985, Ian Chadwick. Reservados todos los derechos.
Edición anterior: derechos de autor de 1983, Irata Press, Ltd. Michael Reichmann, editor.
La reproducción o traducción de cualquier parte de esta obra, más allá de lo permitido por las Secciones 107 y 108 de la Ley de Derechos de Autor de los Estados Unidos, sin la autorización del titular de los derechos de autor, es ilegal.
Impreso en Estados Unidos
10 9 8 7 6 5 4
ISBN 0-87455-004-1
No asumimos ninguna responsabilidad por daños a los programas del lector debido al uso o mal uso de la información aquí presentada. Se recomienda a los lectores leer la advertencia de la introducción sobre el almacenamiento de programas críticos y la extracción de discos o cassettes importantes antes de intentar utilizar este manual.
El autor y el editor han hecho todo lo posible en la preparación de este libro para garantizar la precisión de los programas y la información. Sin embargo, la información y los programas de este libro se venden sin garantía, ni expresa ni implícita. Ni el autor ni COMPUTE! Publications. Inc. serán responsables de ningún daño causado o presuntamente causado, directa, indirecta, incidental o consecuentemente, por los programas o la información de este libro.
COMPUTE! Publications, Inc., Apartado Postal 5406, Greensboro, NC 27403 (919) 275-9809, forma parte de ABC Consumer Magazines, Inc., una de las empresas editoriales de ABC, y no está asociada con ningún fabricante de computadoras personales. Atari 400, 800, 1200XL, 600XL, 800XL, 65XE y 130XE son marcas comerciales de Atari, Inc.
PREFACIO DEL AUTOR A LA EDICIÓN REVISADA
En los últimos dos años, muchas personas me han escrito sobre Mapping, la mayoría con elogios. Me alegró no encontrar errores graves, solo algunas erratas y correcciones menores, todo un homenaje a la habilidad editorial de COMPUTE!. Hay demasiadas personas para mencionarlas a todas, pero agradezco el esfuerzo de ustedes, los lectores; por favor, sigan escribiéndome, aunque no pueda responder a todas las cartas.
Un agradecimiento especial a Joe Miller de Koala Technologies (anteriormente de Atari, autor del disco Translator y usuario frecuente de CompuServe), Matt Ratcliff (operador remoto del BBS Gateway), Randy Tjin de Atari Canadá, Neil Harris y Richard Frick de Atari EE. UU. por su soporte técnico, y Bill Wilkinson por las frecuentes menciones en la revista COMPUTE!, a Gary Yost de Antic y a mi amigo Yoram Rostas por su incesante indagación y análisis de la máquina. También a Atari por su política de "sistema abierto", que hizo posible este libro.
El Atari SIG en CompuServe ha sido de gran ayuda y apoyo; puede que sea la mejor fuente de información y software de dominio público para Atari disponible actualmente. Si no han usado CompuServe, les recomiendo encarecidamente que lo hagan; el operador del sistema, Ron Luks, y su equipo gestionan una excelente operación en línea. Ron me ayudó a recopilar parte de esta información publicando un mensaje especial pidiendo sugerencias y respuestas a mis preguntas.
Sobre todo, le debo un inmenso amor, gratitud y afecto a la siempre paciente Susan McCallan, mi fiel compañera durante los últimos dos años. Nunca he entendido bien cómo me soporta, pero espero que siga haciéndolo durante mucho tiempo. Este libro es para ella.
Publicaciones y productos
Desde la primera edición, OSS ha lanzado un excelente lenguaje nuevo, Action!, así como un BASIC considerablemente superior: el BASIC XL. Action! es probablemente el mejor lenguaje para Atari hasta la fecha; es un poco como C y Pascal, con un toque de Forth. Lo recomiendo. (Russ Wetmore escribió el Atari HomePak en Action!. Incluso la versión para Commodore 64 se escribió en Action! para Atari). Muchas utilidades y programas de Action! también están disponibles en el Atari SIG de CompuServe.
Se han publicado demasiados artículos en revistas desde la edición original como para poder consultarlos todos, pero "Insight: Atari" de Bill Wilkinson en la revista COMPUTE!, "From Here to Atari" de Paul Swanson en la revista Micro, además de artículos en las revistas Analog, Antic, Creative Computing y ROM, han aportado su valiosa información. La revista oficial de Atari, Atari Explorer, también contiene numerosos artículos útiles, especialmente para programadores principiantes.
En cuanto a libros, "Programmer's Reference Guide for the Atari 400/800 computers" de David Heiserman (Howard Sams, 1984) es una buena referencia en un solo volumen. La obra de Mark Chasin, "Assembly Language Programming for the Atari Computers" (McGraw-Hill, 1984), es muy recomendable; ofrece numerosos ejemplos excelentes dirigidos exclusivamente a usuarios de Atari, explicando conceptos tan complejos como E/S, controladores y las VBI. La obra de Carl Evans, "Atari BASIC Faster and Better" (IJG, 1983), es un excelente libro técnico para programadores de BASIC que deseen mejorar su estilo y aprender algo de lenguaje máquina.
Jerry White, reconocido autor de software para Atari, coescribió un excelente compendio con Gary Phillips titulado "The Atari User's Encyclopedia" (The Book Company, 1984). El libro "Advanced Programming Techniques for Your Atari" (Tab, 1983) de Linda Schreiber contiene varias rutinas útiles para gráficos y cadenas de caracteres en BASIC.
COMPUTE! Books ha publicado varios libros de calidad, entre ellos "COMPUTE!'s Third Book of Atari", "COMPUTE!'s First Book of Atari Graphics", "COMPUTE!'s Second Book of Atari Graphics", y el "COMPUTE!'s First Book of Atari Games". Una verdadera delicia para los hackers es "The Atari BASIC Sourcebook", de Bill Wilkinson, Kathleen O'Brien y Paul Laughton, que incluye el código fuente completo del Atari BASIC, una obra imprescindible para los usuarios expertos de BASIC (junto con "Inside Atari DOS" de Wilkinson). Uno de los mejores libros recientes de COMPUTE! es "Lenguaje de máquina para principiantes" de Richard Mansfield, una forma sencilla de introducirse en la programación en lenguaje de máquina.
Por último, para los verdaderos aficionados al hardware, Atari publicó su "400-800 Home Computer Field Service Manual" (N.° de parte FD 100001); contiene una gran cantidad de datos, esquemas, listas de piezas, pruebas de diagnóstico e información de montaje. Es difícil de conseguir, pero vale la pena. También está disponible el "800XL Field Service Manual". Sams ha publicado un excelente manual de servicio técnico de hardware para el 800 y el 800XL; es caro, pero contiene material que cualquier hacker de hardware necesita saber.
Parece que el Atari tendrá una larga vida; ya está en su tercera generación (todas son compatibles). Me alegra ver que el reciente cambio de propietario no significó el fin de mi ordenador doméstico favorito, sino que Jack Tramiel continúa brindándole soporte y desarrollo, además de mantener la compatibilidad entre modelos. Tengo muchas ganas de ver sus nuevas máquinas ST basadas en el procesador 68000.
Marzo de 1985
Ian Chadwick
55 Kent Rd
Toronto, Ontario
M4L 2X5
Canadá
CompuServe 70375,1010
PREFACIO DEL AUTOR
¿Qué es exactamente un mapa de memoria? Es una guía de las ubicaciones de memoria de su computadora. Una ubicación de memoria es uno de los 65.536 bytes donde se almacena un número. Cada byte contiene un número para programas, datos, color, sonido, operación del sistema o está vacío (es decir, tiene un 0), esperando a que lo llene con su propio programa.
Cada byte se compone de 8 bits, cada uno de los cuales puede ser un 1 (activado) o un 0 (desactivado). El área modificable de la memoria que utiliza para sus programas se llama RAM (Random Access Memory - Memoria de Acceso Aleatorio), mientras que el área que usa el Atari para ejecutar sus propios programas se llama ROM (Read Only Memory - Memoria de Solo Lectura). Aunque algunas de las ubicaciones de memoria en los chips especiales del Atari fueron diseñadas para ser escritas como la RAM, el resto de la ROM, incluida la ROM del Sistema Operativo, no puede ser modificada por el usuario, ya que contiene rutinas como el paquete matemático de punto flotante y las rutinas de entrada/salida.
Espero que el lector esté lo suficientemente familiarizado con su Atari como para comprender algunos de estos usos básicos de un mapa de memoria. Este manual no pretende explicar completamente cómo usar las instrucciones PEEK y POKE; consulte su manual del BASIC. En resumen, PEEK permite visualizar el valor almacenado en cualquier ubicación de memoria. Si desea que ese valor se imprima en pantalla, debe anteponer la instrucción PEEK con una instrucción PRINT, como por ejemplo:
PRINT PEEK (708)Si no ha cambiado los registros de color, esto devolverá el número 40 en la pantalla. Todos los bytes del Atari pueden contener un número entre 0 y 255. POKE permite introducir un valor en un byte, como por ejemplo:
POKE 755,4¡Al hacer esto, ha invertido el texto! Puede devolverlo a la normalidad haciendo:
POKE 755,2De igual forma, ¡POKE 710,80 pintará la pantalla de morado oscuro! Al igual que con PEEK, POKE solo admite números entre 0 y 255. No podrá usar POKE en la mayoría de las ubicaciones de la ROM, ya que los números en muchas de ellas están grabados en el chip y no se pueden modificar de esta manera.
Entonces, ¿cómo almacena el Atari (u otras microcomputadoras de 8 bits, de hecho) un número mayor que 255? Dividiéndolo en dos partes: el byte más significativo (MSB - Most Significant Byte), que es el número dividido entre 256 y redondeado al entero más cercano, y el byte menos significativo (LSB - Less Significant Byte), que es el número original menos el MSB. El Atari sabe que debe multiplicar el MSB por 256 y sumar el LSB para obtener el número. Por ejemplo, el número 45.290 se almacena en dos partes: 234 (LSB) y 176 (MSB). 176 por 256 es igual a 45056, más 234 es igual a 45.290.
ALMACENAMIENTO MENOS-MÁS
El Atari utiliza la convención de almacenar direcciones en memoria en formato LSB/MSB (Least Significant Byte/Most Significant Byte - Byte Menos Significativo/Byte Más Significativo. Es decir, la parte más pequeña se encuentra en la primera posición). Por ejemplo, las posiciones 88 y 89 almacenan la dirección más baja de la memoria de la pantalla. Supongamos que los números encontrados allí son 22 y 56, respectivamente. Para obtener la dirección decimal, se toma el byte más significativo (almacenado en 89) y se multiplica por 256, y luego se suma al byte menos significativo en la ubicación 88. En nuestro caso, 56 * 256 es igual a 14.336, más 22 es igual a 14.358. Esta es la dirección de la esquina superior izquierda de la pantalla. Una forma sencilla de hacerlo en BASIC es:
BYTE = PEEK (88) + PEEK (89) * 256El proceso inverso (dividir una ubicación decimal en sus componentes MSB y LSB) se realiza de la siguiente manera:
MSB = INT (BYTE/256):LSB = BYTE - MSB * 256Este proceso es más fácil para los programadores de lenguaje ensamblador que utilizan números hexadecimales, ya que los dos dígitos de la derecha son siempre el LSB Y los dos de la izquierda son el MSB. Por ejemplo:
$D016 (hexadecimal para 53.270) es igual a 16 (LSB) y D0 (MSB)$16 equivale a 22 en decimal y $D0 equivale a 208 en decimal. Multiplique el MSB por 256 y sumele 22, lo que da como resultado 53.270. En la sección de mapas de este libro, he proporcionado números decimales y hexadecimales juntos para facilitar su consulta. En el BASIC de 8K, solo se pueden usar números decimales con POKE, y PEEK solo devolverá valores decimales.
El hexadecimal es un sistema de base 16 que se utiliza en lugar del sistema de base 10 normal porque se adapta mejor a la estructura de 8 bits de la computadora. Por lo tanto, cuando decimos 2.175 en decimal, lo que realmente queremos decir es:
10.000 1.000 100 10 1 0 2 1 7 5En hexadecimal, el mismo número es $87F. Esto se descompone en:
4096 256 16 1 0 8 7 FEn lugar de multiplicar cada paso por diez, lo multiplicamos por 16. Bien, pero ¿de dónde sacamos la "F"? Bueno, si la base diez tiene los números del cero al nueve, a la base 16 habría que añadirle algunas letras al final para compensar los números extra:
Decimales 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Hexadecimal 0 1 2 3 4 5 6 7 8 9 A B C D E FEntonces, $F equivale a 15 en decimal. Así es como se relaciona todo con las matemáticas binarias y los bits:
Cada byte se puede dividir en dos partes (nybbles), de la siguiente manera:
0000 0000Si cada nibble se considera un número independiente, en decimal, su valor oscila entre 0 y 15, o entre 0 y $F. ¡Ajá! Entonces, si todos los bits de cada grupo son igual a 1 (han sido establecidos o activados), entonces tiene:
1111 1111 Binario 15 15 Decimal FF HexAl unir los dos números hexadecimales, se obtiene SFF (255 en decimal), el máximo número que puede contener un byte. Así, se puede ver cómo traducimos bytes de binario a hexadecimal, traduciendo cada nibble. Por ejemplo:
1001 1101 Binario 9 13 Decimal 9 D Hex$9D equivale a nueve veces 16 más 13, ó 157 en decimal.
0100 0110 Binario 4 6 Decimal 4 6 Hex$46 equivale a cuatro por 16 más seis, ó 70 en decimal.
1111 1010 Binario 15 10 Decimal F A Hex$FA equivale a 15 por 16 más 10, ó 250 en decimal. ¡Obviamente, es más fácil calcularlo con un programa de traducción o una calculadora!
Dado que a menudo hablaré sobre la configuración de bits y explicaré brevemente su arquitectura, es importante que conozca los procedimientos sencillos para activar y desactivar bits específicos en cualquier ubicación (es decir, cómo manipular uno de los 8 bits individuales dentro de un byte). Cada byte es un conjunto de 8 bits: los números se representan activando los bits específicos que suman el número almacenado en ese byte. Los bits pueden ser cero (0 = desactivado) o uno (1 = activado o establecido). Los bits están numerados del 0 al 7 y representan los siguientes números decimales:
Bit 7 6 5 4 3 2 1 0 Valor 128 64 32 16 8 4 2 1La relación entre los bits y las potencias de dos debería ser obvia. Sumar todos los números (todos los bits están activados) da como resultado 255. Por lo tanto, cada byte puede contener un número entre 0 (ningún bit activado) y 255 (todos los bits activados).
A veces, en lugar de 0, "ningún bit activado" significa 256. Esto se indicará en las ubicaciones correspondientes. Entonces, ¿cómo se activa un bit? Simple: haga POKE con el número apropiado. Por ejemplo, para activar el bit 5, haga POKE la ubicación con el número 32. Para activar los bits 7, 5 y 4, sume sus valores, 128 + 32 + 16, y haga POKE en la ubicación con el total: 176.
A veces es necesario activar un bit sin cambiar otros bits ya activados, por lo que se hace:
POKE número, PEEK (número) + valor decimal del bit que se va a activar (es decir, POKE 50418, PEEK (50418) + 32).
Para desactivar un bit, en lugar de sumar el valor, se resta con el número: se hace POKE número, PEEK (número) menos el valor decimal del bit a desactivar. Las matemáticas binarias son sencillas y fáciles de aprender; si no las entiende ahora, debería investigar más sobre lenguaje máquina antes de intentar usar esta guía en serio.
AND, OR Y EOR
Es útil que el lector sepa cómo ejecutar lógica booleana con bits. Existen tres funciones en código ensamblador para manipular bits de esta manera: AND, OR y EOR (OR exclusivo). Cada una requiere el uso de dos números: el que se procesa y el que se utiliza para realizar la función. A continuación, se presenta una breve explicación de cómo funcionan estas funciones lógicas:
El operador AND se usa generalmente como máscara para eliminar los bits no deseados. Se comparan dos números binarios usando AND; si ambos bits en la misma posición son 1, el resultado es 1. Si alguno de los bits es 0, el resultado es 0. Por ejemplo:
51 = 00110011 AND 15 = 00001111 -------- Resultado = 00000011 = 3OR se usa frecuentemente para forzar lel establecimiento en 1 de un bit. Si un bit en el número original o en la máscara es igual a 1, el resultado es 1. Por ejemplo
65 = 01000001 OR 128 = 10000000 -------- Resultado = 11000001 = 193En este caso, 65 es la "A" de ATASCII. Al combinarlo con 128, obtenemos 193, el código ATASCII de la letra la "A" en video inverso.
EOR "invierte" los bits del original si la máscara tiene un 1 en la misma ubicación. Por ejemplo:
193 = 11000001 EOR 128 = 10000000 -------- Resultado = 01000001 = 65En este caso, hemos devuelto el código ATASCII de la letra "A" en video inverso a su valor normal. Un EOR con 255 (todos los bits igual a 1) producirá el complemento del número:
171 = 10101011 EOR 255 = 11111111 -------- Resultado = 01010100 = 84En resumen:
Original: Máscara: AND: OR: EOR: 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 1 1 1 0Atari BASIC admite AND, OR y NOT; NOT es el complemento lógico donde NOT1 es igual a 0 y NOT0 es igual a 1. Si la expresión es verdadera, se obtiene un 0; si no es verdadera, se devuelve un 1; por ejemplo, NOT ((3 + 4) >= 6) da como resultado 0. Para obtener una rutina en lenguaje máquina que permite realizar lógica de bits booleana mediante una llamada USR desde BASIC, consulte la revista COMPUTE! de mayo de 1981.
En general, he intentado evitar el uso de mnemónicos del lenguaje ensamblador del 6502, pero los he incluido cuando consideré que su uso describía la acción a realizar mejor que una explicación extensa. Los más comunes son JMP (saltar a una ubicación), JSR (saltar a subrutina), RTS (regresar de la subrutina) y RTI (regresar de la interrupción). Los lectores deben tener conocimientos mínimos de lenguaje de máquina para comprender las subrutinas utilizadas aquí.
También sugiero que, si el lector aún no lo tiene, consiga un programa para traducir de hexadecimal a decimal y de decimal a hexadecimal (posiblemente incluso uno con traducción a binario). El cartucho ROM Monkey Wrench de Eastern House Software es útil para este propósito. Quizás la calculadora TI Programmer de Texas Instruments sea la más fácil de usar.
Los ejemplos de este libro se escribieron con el BASIC Atari de 8K. Su objetivo es demostrar el uso o el efecto de una ubicación de memoria específica. No pretenden ser los mejores ejemplos de programación en BASIC; se escribieron para simplificar, no para sofisticar.
Como nota final, cualquier pregunta o duda sobre una ubicación o explicación en particular ha sido anotada. No está de más experimentar un poco, explorando la memoria para ver qué otros efectos se pueden descubrir. Si encuentra algo que yo no haya encontrado, ¡genial! Por favor, escríbame y hágamelo saber.
Explorar la memoria no dañará la máquina, aunque podría bloquear cualquier programa, así que guarde su programa primero. Normalmente puede recuperarlo pulsando RESET, pero puede que tenga que apagar el equipo y reiniciarlo de vez en cuando. Puede aprender mucho sobre su equipo simplemente probando.
SOBRE LOS LENGUAJES DE PROGRAMACIÓN
La mayor parte de la información aquí presentada se refiere a ubicaciones independientes del lenguaje que utilice para programar. Cuando la ubicación depende del lenguaje, como las áreas del BASIC o del DOS, lo he indicado en la sección correspondiente. Puedes ejercer el mismo control sobre su Atari en FORTH, Pascal, LISP o cualquier lenguaje que elija. Obviamente, tendrá que cambiar los comandos PEEK y POKE por los comandos adecuados para su lenguaje.
BASIC es un buen lenguaje para empezar: puedes usarlo para aprender a programar, explorar su computador, experimentar y divertirse. Sin embargo, cuando esté listo para continuar, y si realmente quieres sacar el máximo provecho de su Atari, tendrá que aprender un lenguaje más eficiente y rápido. Mucha gente elige el lenguaje máquina del 6502 por su velocidad.
Si prefiere seguir con un lenguaje de alto nivel, le sugiero que aprenda FORTH. Tiene la velocidad del código en lenguaje de máquina con la facilidad de la programación de los lenguajes de alto nivel.
Los lenguajes de programación, cualquiera que se use, tienen un significado bastante preciso, especialmente en comparación con el inglés. Tenga en cuenta que en inglés, una probabilidad alta y una probabilidad baja1 significan lo mismo. Sin embargo, "POKE", "PUT" y "PUSH" tienen significados muy diferentes en la jerga informática.
1 En la versión original en inglés, los términos son "fat chance" y "slim chance". (N. del T.)
ESTRUCTURA DEL TEXTO
Ejemplo: 912-927 390-39F IOCB5
El mapa de memoria principal muestra la ubicación decimal y luego la hexadecimal, la etiqueta (asignada por Atari y utilizada por las rutinas del Sistema Operativo, DOS o DUP), y luego los comentarios y la descripción. La etiqueta no tiene una función real; es simplemente una utilidad mnemotécnica. Se recomienda a los lectores consultar el excelente libro de Stan Kelly-Bootle, "The Devil's DP Dictionary" (McGraw-Hill Ryerson, 1981), para obtener una definición completa de la palabra "etiqueta". Las siguientes abreviaturas también se indican en los comentarios:
(L) Leer (E) EscribirA veces las funciones son diferentes en una ubicación particular, por lo que se anota cada una.
(D:) Unidad de disco (E:) Editor (S:) Pantalla (K:) Teclado (P:) Impresora (C:) Cassette (R:) Interfaz RS-232.(número) p. ej., (708) Registro Sombra. Este es un registro RAM correspondiente a un registro ROM de uno de los chips especiales de Atari, como GTIA o POKEY. La ubicación sombra es la dirección que se usa para los valores PEEK y POKE. Estas ubicaciones sombra son consultadas por las direcciones de hardware 30 veces por segundo en cada etapa 2 del intervalo del VBLANK, y los valores utilizados se transfieren a las ubicaciones de hardware para su uso. Para efectuar cualquier cambio "permanente" en la ubicación del hardware, en BASIC se debe usar el registro sombra (por supuesto, ¡todo cambio se invalida al apagar la máquina!). Solo el lenguaje de máquina es lo suficientemente rápido como para usar las direcciones hardware directamente.
Por ejemplo, la posición 54273 es para el control de caracteres. Consulta la posición 755 para determinar si los caracteres de la pantalla deben ser normales, en video inverso o invertidos. Para cambiar los caracteres, se hace POKE en la posición 755 (la sombra), y no en la ubicación 54273. Si se hace poke a la ubicación 54273, se obtendrá el efecto deseado ¡pero sólo durante 1/60 de segundo! Como se mencionó anteriormente, se pueden usar las direcciones hardware directamente en lenguaje máquina, pero no en BASIC. Es demasiado lento.
A veces, cuando sea más apropiado, se mostrará un número hexadecimal y el número decimal se colocará entre paréntesis. El contexto debe ser claro respecto a cual de ellos es un número decimal o un registro sombra.
(* letra) se refiere a una fuente en caso de conflicto entre la ubicación o la explicación. Véase la fuente a continuación.
($número) se refiere a un número hexadecimal (p. ej.: $D40E). También me refiero a las "páginas" de memoria. Las páginas son secciones de 256 bytes ($100) de memoria que terminan en 00 (p. ej.: $E200, $C000, $600). Cuatro páginas ($400) equivalen a 1024 bytes o 1 kB (kilobyte) de memoria.
GLOSARIO
ANTIC, CTIA Y GTIA, PIA Y POKEY: Chips especiales del Atari que controlan los gráficos, el color y la resolución de la pantalla, los conectores de los controles y el sonido del Atari 400/800, respectivamente. Se encuentran en la ROM, en las posiciones 53248 a la 54783. ANTIC también procesa las interrupciones no enmascarables y POKEY procesa las solicitudes de interrupción. Estos chips, junto con el microprocesador 6502 que se encarga de hacer funcionar el resto del Atari, se encuentran dentro del computador, protegidos por el blindaje metálico bajo la cubierta de plástico.
BIT, BYTE: Un bit es la división de memoria más pequeña de su computadora. Es tan pequeño que solo puede contener un valor: apagado (0) o encendido (1). 8 hits juntos forman un byte; este es el tamaño de las ubicaciones de memoria que se describen en este libro. A veces oirá a los programadores hablar de medio byte, llamado "nybble".
CIO: Central Input Output. Rutinas centrales de entrada/salida ubicadas en la ROM. Controlan las operaciones del bloque de control de entrada/salida. En resumen, CIO gestiona la entrada y salida de datos a través de los controladores de dispositivo (también conocidos como device driver o device handler) y luego transfiere el control a dichos controladores. Es una interfaz única que permite acceder a todos los periféricos de forma independiente (es decir, un manejo uniforme de los datos sin importar el dispositivo al que se accede). Por ejemplo, escribir datos en un archivo de disco se trata de la misma manera que escribir datos en la pantalla; las comas insertan espacios en blanco entre los elementos, y tanto el punto y coma como la coma suprimen al carácter de fin de línea (EOL).
DCB: Device Control Block. Bloque de control de dispositivo, utilizado por la entrada/salida serie.
DL: Display List. Lista de Despliegue. Este es un conjunto de instrucciones que indican al chip ANTIC dónde encontrar los datos de visualización y cómo deben colocarse en la pantalla del televisor.
DLI: Display List Interrupt. Interrupción de Lista de Despliegue. Una DLI hace que la pantalla detenga su procesamiento para ejecutar temporalmente una rutina escrita por el usuario.
DOS: Disk Operating System. Sistema Operativo de Disco. El software cargado desde el archivo de disco DOS.SYS que controla todas las E/S del disco. La última edición del DOS se llama DOS 2.0S (S de densidad única (single)).
DUP: Disk Utilities Package. Paquete de Utilidades del Disco. El software cargado desde el archivo de disco DUP.SYS, que gestiona las distintas funciones del menú DOS, como Copiar.
FMS (o, a veces, DFMS): File Management System. Parte del sistema de gestión de archivos del DOS; es un controlador de dispositivo dedicado que controla todas las operaciones de E/S del dispositivo "D:".
FP: Floating Point. Paquete matemático de coma flotante que reside en la ROM.
I/O: Input/Output. Entrada/Salida.
IOCB: Input Output Control Block. Bloque de Control de Entrada/Salida. Área de la memoria RAM (ubicaciones 832 a la 959) utilizada por CIO para definir operaciones en dispositivos como la unidad de disco (D:), la impresora (P:), la pantalla (S:), el teclado (K:) y el editor de pantalla (E:). ZIOCB es el IOCB de la Página Cero.
IRQ: Interrupt request. Solicitud de interrupción utilizada para la comunicación del puerto serie, dispositivos periféricos, temporización y entrada de teclado. Las IRQ son procesadas por el chip POKEY.
NMI: Non-maskable interrupt. Interrupción no enmascarable; se utiliza para la visualización del video y el reinicio. Las NMI son procesadas por el chip ANTIC.
OS: Operating System. Sistema Operativo. El sistema residente que ejecuta el Atari. El OS reside en la ranura frontal para los cartuchos de 10K, bajo la cubierta del Atari 800. No es visible en el 400 sin desmontar la cubierta (no recomendado). El OS es el mismo para el 400 y el 800. Actualmente existen 2 versiones del OS en circulación: la ROM "A" (antigua) y la ROM "B" (la más reciente), lanzadas alrededor de enero de 1982. El nuevo OS es casi idéntico al anterior, salvo que corrige algunos errores y cambia algunas direcciones. No todo el software antiguo funcionará con el nuevo OS. Las diferencias entre ambos se explican mejor en el Apéndice Cuatro. Aunque a menudo se hace referencia a toda la ROM como OS, esto no es correcto. La ROM del OS es la parte de la memoria que contiene el paquete de coma flotante, el conjunto de caracteres de Atari, los controladores de dispositivos y tanto CIO como SIO. El Sistema Operativo en sí es la parte de la ROM del OS que gestiona la E/S.
Gráficos PM, PMG: Player/Missile graphics. Gráficos de player/missile. Los players y misiles son objetos de pantalla especiales, móviles, definidos por el usuario y con colores. Se suelen usar para juegos, animaciones o cursores especiales. Los gráficos PM son únicos porque permiten establecer la forma (prioridad) en que interactúan con el resto de la pantalla y entre sí.
RAM: Random access memory. Memoria de Acceso Aleatorio. Toda la memoria por debajo del área del Sistema Operativo (ubicaciones 0 a la 49151) que se utiliza para almacenamiento, programas, búferes, cartuchos, DOS, IOCB, registros sombra y registros de los chips especiales de Atari. El acceso aleatorio significa que se puede acceder a estas ubicaciones aleatoriamente, y no que se almacene la información de manera aleatoria.
ROM: Read-only memory. Memoria de Solo Lectura. La parte de la memoria de alta capacidad (ubicaciones 49152 a la 65535) donde residen los chips de hardware especiales y el Sistema Operativo. La ROM también se usa para describir la memoria de cartucho, como la ROM del BASIC de 8K, que no puede ser modificada por el usuario (la ROM del cartucho reemplaza a la RAM). La mayor parte de la ROM no se puede modificar, aunque algunas ubicaciones en los chips especiales de Atari pueden configurarse temporalmente con un nuevo valor. Tanto en RAM como en ROM, las áreas con valores menores se denominan memoria "baja" y las ubicaciones con valores mayores, memoria "alta".
SIO: Serial input output. Rutinas de entrada/salida serie ubicadas en la ROM. Controla las operaciones serie, incluyendo la interfaz Atari 850 (R:) y la grabadora de cassettes (C:). En resumen, SIO controla los periféricos Atari según la solicitud realizada en su Bloque de Control de Dispositivos (DCB) por el controlador de dispositivo correspondiente. FMS también accede a él para la transferencia de datos.
VBI: Vertical blank interrupt. Interrupción del VBLANK. Una VBI es una interrupción que ocurre durante el intervalo VBLANK, lo que provoca que el computador salte a una ubicación especificada por el usuario para procesar una rutina corta escrita por él durante el proceso VBLANK.
VBLANK: Vertical blank. Blanqueo Vertical. El intervalo entre el momento en que el haz de electrones del televisor se apaga tras alcanzar la esquina inferior derecha de la pantalla y regresa a la esquina superior izquierda para volver a encenderse. Este breve periodo de tiempo puede ser utilizado por los programadores en lenguaje máquina para rutinas cortas sin interrumpir la visualización mediante la escritura de un VBI (vea la ubicación de arriba). VBLANK consta de 2 etapas. La primera se realiza cada ciclo (1/60 de segundo). La segunda se realiza cada 1/30 de segundo o cada 1/60 de segundo, cuando no se interrumpe la ejecución de código crítico. Consulte el final del mapa de memoria para ver los procesos ejecutados en cada etapa.
FUENTES
En esta guía se utilizan letras entre paréntesis para identificar la fuente2.
(*M) Master Memory Map Ver. 2, Santa Cruz Educational Software, 1981. Una guía de memoria delos mismos creadores de la serie TRICKY TUTORIAL. Estos últimos son tutoriales y utilidades de aplicación. El mapa contiene algunas erratas molestas.
(*Y) Your Atari Computer, de Lon Poole con Martin McNiff y Steven Cook, Osborne/McGraw-Hill, 1982. La mejor guía a la fecha sobre el uso general del Atari. Muy recomendable.
(*C) COMPUTE!'s First Book of Atari, de los editores de la revista COMPUTE!, Small System Services Inc., 1981. Una buena colección de los primeros artículos publicados en la revista. Al momento de escribir esto, el COMPUTE!'s Second Book of Atari acaba de publicarse. Por lo tanto, no se utiliza aquí como fuente de referencia, pero es imprescindible para los programadores experimentados. Contiene abundante información sobre una amplia gama de temas, incluyendo gráficos avanzados, modos de lectura forzada, cambio de página, Atari BASIC y muchas utilidades valiosas. Debería ser un recurso indispensable en la biblioteca de la mayoría de los usuarios Atari.
(*I) Inside Atari DOS, compilado por Bill Wilkinson, publicado por COMPUTE! Books, Small System Services, Inc., 1982. Una explicación y código fuente con derechos de autor para la sección FMS de DOS 2.0.
Atari BASIC: Learning by Using, por Thomas Rowley, Hofhacker Press, 1981. Mucha información condensada en un libro sorprendentemente bueno.
Las siguientes publicaciones son todas de Atari, Inc. Las recomiendo a todos los interesados en comprender sus computadores Atari:
(*D): De Re Atari: una referencia arcana, pero indispensable, sobre el funcionamiento de Atari y algunos de sus aspectos más impresionantes, por Chris Crawford y otros. Publicado por entregas en la revista BYTE, entre finales de 1981 y mediados de 1982. Las ediciones anteriores contienen algunas erratas, así que asegúrese de obtener la edición más reciente.
(*O) Manual del Usuario del Sistema Operativo y
(*H) Manual del Hardware de Atari. La famosa pareja de "manuales técnicos". Imprescindible para usuarios exigentes, aunque extenso y, por lo general, poco profesional en la presentación del material.
(*8) Manual de la interfaz Atari 850. El manual del 850 ofrece numerosos ejemplos en BASIC sobre cómo usar los puertos de interfaz serie RS232 para el control de impresoras y telecomunicaciones. El excelente programa de terminal llamado Jonesterm, escrito en BASIC con subrutinas en lenguaje máquina, es de dominio público y está disponible en muchos sistemas de tablón de anuncios electrónicos, incluyendo CompuServe. Los usuarios de módem encontrarán muchos programas útiles en CompuServe.
(*L) Listado del código fuente del Sistema Operativo y
(*U) Listado del código fuente de las Utilidades del Disco son los listados del código fuente comentados y con derechos de autor del Sistema Operativo y la parte DUP.SYS del DOS.
(*B) Manual de Referencia del BASIC de Atari.
(*S) Manual del DOS.
(*A) Manual del BASIC de Microsoft. El BASIC de Microsoft hace un excelente uso de PEEK y POKE para realizar numerosas tareas. También incluye muchos comandos potentes que no están disponibles en el BASIC de 8K.
2 La única fuente citada usando la nomenclatura detallada aquí corresponde a (*M) "Master Memory Map Ver. 2" en las ubicaciones DINDEX (87; $57) y SKCTL (53775; $D20F). (N. del T.)
REVISTAS
La revista ANTIC publicó un extenso mapa de memoria, escrito por James Capparell, que se extendió a lo largo de varios números. Cuando se utilizó como fuente, etiqueté estas referencias con (AM)3. Contiene algunas erratas menores.
Encontré útiles varios artículos de revistas, en particular los de COMPUTE! y Creative Computing. También encontré útiles las revistas Softside, BYTE, ANALOG y Micro para la preparación de este libro. Todas ellas se mencionan a lo largo del libro por mes o número. Agradecemos especialmente al equipo de Atari que publicó los manuales técnicos y los listados de fuentes del Sistema Operativo y del DOS. También agradecemos a Bill Wilkinson, de Optimized Systems Software Inc., quien creó la parte DUP del DOS y decidió publicar el código fuente en su libro Inside Atari DOS. Ningún otro fabricante de computadoras, que yo sepa, ha proporcionado jamás a los usuarios material tan completo ni los detalles de sus propios sistemas operativos. Sin él, nada de esto habría sido posible: gran parte de la información aquí presentada se obtuvo de dichas fuentes.
Este libro está organizado en cuatro secciones: una lista numérica de las principales ubicaciones de memoria de Atari, sus etiquetas y su uso; un mapa o diagrama general para mostrar cómo se compone la memoria; un apéndice de material de utilidad con gráficos y tablas, y una guía de índice/referencia cruzada.
Hay muchísima información aquí; por tedioso que parezca, le sugiero que lea este manual completo al menos una vez. Parte de la información que no esté clara en un área puede ser ampliada y aclarada en otra. Si se hace referencia a otra ubicación en una descripción, debe consultar la referencia y leerla después de haber leído la primera ubicación. También debe consultar las ubicaciones utilizadas en cualquier programa de ejemplo. Cuanto más familiarizado esté con la memoria, más provecho le sacará a su Atari. Para obtener más información, al leer la descripción de cualquier ubicación de memoria, asegúrese de consultar el registro sombra o el registro hardware mencionado.
3 La única revista citada usando la nomenclatura detallada aquí corresponde a (AM) "Antic Magazine" en la ubicación BUFSTR (108,109; $6C,6D) (N. del T.)
ENCENDIDO Y REINICIO
ARRANQUE EN FRÍO
Al encender la computadora, el Sistema Operativo de Atari realiza diversas funciones, algunas de las cuales se indican como predeterminadas en las ubicaciones de memoria a seguir. Entre estas funciones se encuentran:
Determinar la dirección de RAM más alta y borrar toda la RAM con ceros (excepto las ubicaciones de la 0 a la 15; $0 a la $F).
Borrar y dar formato a la tabla de dispositivos.
inicializar todos los controladores S:, E:, K:, P:, C:, SIO, CIO y el procesador de interrupciones.
Establecer la pantalla en modo gráfico 0, 24 líneas por 40 columnas; configurar los márgenes de pantalla.
Inicializar el(los) cartucho(s), si están presentes; luego comprobar el cartucho B (derecho) y luego el cartucho A (izquierdo).
Verificar las ranuras del cartucho para obtener instrucciones de arranque del disco y, si están presentes, del disco de arranque.
Transferir el control al cartucho o al programa iniciado.
Inicializar los vectores de interrupción de la RAM en las ubicaciones de la 512 a la 548 ($200 a la $224).
Almacenar 0 en los siguientes registros de hardware: 53248 al 53503, 53760 al 54527 ($D000 al $D0FF, $D200 al $D4FF).
Comprobar la bandera de la tecla START y, si está configurada (se mantiene presionada la tecla START), CKEY (74; $4A) solicita un arranque desde el casssette.
Inicializar HATABS (794; $31A) para que apunte a los controladores de dispositivos residentes en la ROM.
El IOCB #0 se abre para dispositivo E:.
El arranque en frío (al encender) básicamente borra por completo el equipo y solo debe usarse para ese fin. Es bastante drástico.
ARRANQUE EN CALIENTE
Cuando se presiona la tecla RESET, el Sistema Operativo realiza algunas de las mismas funciones que durante el encendido, así como también algunas funciones únicas, entre ellas:
Establecer la bandera de inicio en caliente (ubicación 8) en verdadero (255; $FF).
Limpiar la porción del Sistema Operativo de la RAM de las ubicaciones 16 a la 127 ($10 a la $7F) y 512 a la 1023 ($200 a la $3FF).
Restablecer todos los vectores de interrupción de RAM.
Reformatear la tabla del controlador de dispositivos (HATABS); se pierden los vectores recientemente añadidos.
Reinicializar el(los) cartucho(s).
Regresar al modo gráfico 0.
Transferir el control al cartucho o al programa activado.
Restaurar los valores predeterminados en RAM.
Tenga en cuenta que un RESET no borra la RAM, sino que la deja intacta. Normalmente, su programa y sus variables estarán seguros al pulsar la tecla RESET. Esto es considerablemente menos drástico que el reinicio indicado anteriormente.
Existen 2 vectores para la inicialización, para que estos procesos puedan ser invocados por el usuario: 58484 ($E474) para RESET y 58487 ($E477) para el encendido.
Consulte las páginas 109 a la 112 el Operating System Owners Manual, y el libro De Re Atari para ver un diagrama de flujo del proceso.
INTRODUCCIÓN
Bill Wilkinson
Cuando los editores de COMPUTE! me pidieron que escribiera esta introducción, al principio dudé un poco. ¿Cómo se puede presentar lo que es esencialmente un mapa de las ubicaciones importantes del Atari, si no es diciendo "Este es un mapa de..."?
Y, sin embargo, este libro tiene algo que lo convierte en algo más que un simple mapa. Al fin y al cabo, si fuera un mapa de memoria, podría usarlo para aprender que "SSKCTL" es el "control del puerto serie" y que se encuentra en la ubicación $232. Pero ¿qué significa eso? ¿Por qué querría controlar el puerto serie? ¿Cómo lo controlaría?
El valor de este libro, entonces, no reside tanto en el mapa en sí, sino en las explicaciones de las diversas funciones y controles, y sus implicaciones. Aunque me considero bastante familiarizado con el Atari (y su sistema operativo basado en ROM), espero usarlo a menudo.
Hasta ahora, si necesitaba usar una ubicación desconocida en los registros del hardware, primero tenía que localizar el listado correcto, luego encontrar la rutina correcta, averiguar por qué y cómo accedía a ese registro y, finalmente, asegurarme de que no hubiera otras rutinas que también accedieran a ese mismo registro. ¡Uf! Ahora abriré este libro, iré a la página correcta, averiguaré lo que necesito saber y empezaré a programar.
Bien. Hasta aquí esta introducción. Y si se siente cómodo programando en su lenguaje nativo, el que mejor domine, y dos o tres lenguajes más, no necesita más de mí. ¡Mucha suerte y bon voyage!
Un Problema Común
¿Qué? ¿Sigue conmigo? ¿Significa eso que no se siente cómodo accediendo a la memoria en 3 o 4 lenguajes? Bueno, a decir verdad, yo tampoco. Así que decidí que lo más valioso de esta introducción sería un resumen de cómo acceder a la memoria desde no menos de siete lenguajes diferentes. (¿O son ocho? Bueno...).
El título de esta sección puede ser un poco engañoso (a propósito, por supuesto. Como pueden atestiguar quienes leyeron mi columna "Insight: Atari" en la revista COMPUTE!). El "problema común" que analizaremos aquí no es un problema de errores. Es un problema de tareas que ocurre en muchos programas comunes. O quizás podríamos plantearlo como un cuestionario. ¿Por qué no?
Cuestionario: Diseñe un conjunto de rutinas que (1) alteren la posición actual del cursor (en cualquier modo gráfico estándar del Sistema Operativo) a la posición horizontal y vertical especificada por las variables "H" y "V", y (2) recupere la posición actual del cursor de forma similar. Para obtener la máxima puntuación en este problema, implemente la rutina en al menos siete lenguajes de programación diferentes. Nuestra primera tarea será decidir qué siete lenguajes usaremos. El primer paso para la solución: averiguar qué lenguajes están disponibles en los ordenadores Atari. Aquí está mi lista:
Atari BASIC
BASIC A+
Atari Microsoft BASIC
Forth
C
Pascal
PILOT
LISP
Ensamblador/Lenguaje de Máquina
¿Coincide con los suyos? No vale conocer más de un ensamblador ni más de un Forth. Y, de hecho, no debería reconocer el BASIC de Microsoft, ya que usa exactamente el mismo método que el BASIC de Atari. Y le adelanto que no intentaré esta tarea en LISP. Si es un fanático de LISP, mejor para usted; pero no tengo ni idea de cómo abordar el problema con LISP de Datasoft (el único LISP disponible actualmente en Atari). En fin, abordemos estos lenguajes uno por uno.
Atari BASIC y Microsoft BASIC
Bueno, ¿qué tal si hacemos 2 a la vez en esta oportunidad? La implementación es la misma para ambos lenguajes.
De hecho, la primera parte de este conjunto de problemas ya está hecha en Atari BASIC: la instrucción POSITION hace exactamente lo que queremos (POSITION H,V realizará la tarea asignada). Pero eso es trampa, ya que el objetivo de estos problemas es descubrir cómo acceder a nivel de la máquina sin tales ayudas.
El primer paso es examinar el mapa de memoria y descubrir que COLCRS, en las posiciones 85 y 86, corresponde a la columna actual del cursor gráfico (COLumn of CuRSor). Además, ROWCRS (ROW of CuRSor) en la posición 84 es la fila actual del cursor gráfico.
Abordemos primero la fila. Suponiendo que el número de fila está en la variable "V" (como se especificó anteriormente), podemos establecer la fila del cursor mediante el comando "POKE 84,V". Y, de forma similar, podemos decir "V = PEEK(84)" para asignar la posición actual a "V". Esto es bastante sencillo: para cambiar una sola ubicación de memoria, use "POKE dirección,valor"; para recuperar el contenido de una sola ubicación de memoria, use "PEEK(dirección)". Prácticamente cualquiera que haya programado en BASIC en un Atari conoce al menos la existencia de PEEK y POKE, ya que es el único método para acceder a ciertas funciones de la máquina (dado que los programas de juegos publicados en revistas están repletos de PEEKs y POKEs).
Pero ahora veamos la columna del cursor, especificada en las ubicaciones 85 y 86, un valor de "dos bytes". ¿Qué significa esto? ¿Cómo puede algo ocupar 2 ubicaciones? En realidad, todo se debe a que una sola ubicación (byte, celda de memoria, carácter, etc.) en un computador Atari solo puede almacenar 256 valores diferentes (normalmente numerados del 0 al 255). Si se necesita almacenar un número mayor, se deben usar más bytes. Por ejemplo, 2 bytes contiguos pueden almacenar 65.536 valores diferentes, 3 bytes pueden almacenar 16.777.216 valores diferentes, etc.
Dado que un modo gráfico de Atari puede tener hasta 320 columnas, no podemos usar una sola ubicación de un byte para almacenar el número de columna. ¡Genial! Simplemente usaremos 2 bytes y le indicaremos a BASIC que queremos comunicarnos con una celda de memoria más grande. ¿Qué es eso? ¿No puede decirle a BASIC que use una celda de memoria más grande? ¡Uy!
Ah, pero tranquilo. Aún podemos realizar la tarea; solo requiere un poco más de trabajo en BASIC. El primer subproblema es dividir el número de columna (variable "H") en dos "partes": una para el primer byte y otra para el segundo. La forma más clara de lograrlo es con el siguiente código:
H1 = INT(H/256) H2 = H - 256 * H1Debido a la naturaleza de la aritmética del lenguaje de máquina, los números diseñados para ser enteros de 2 bytes generalmente deben dividirse tal como se muestra: el byte de mayor orden debe obtenerse dividiendo el número por 256, y cualquier fracción del cociente debe descartarse. El byte de menor orden es, en realidad, el residuo después de extraer todas las unidades de 256 (a menudo denominado "el número módulo 256"). Por lo tanto, si obtuvimos "H1" y "H2" como se indicó anteriormente, podemos cambiar la fila del cursor de la siguiente manera:
POKE 85,H2 POKE 86,H1¡Observe la inversión del orden de los bytes! Para Atari (y muchas otras microcomputadoras), el byte de orden inferior (o menos significativo) viene primero en la memoria, seguido del byte de orden alto (o más significativo).
Ahora, supongamos que queremos evitar el uso de las variables temporales "H1" y "H2" y que, además, queremos escribir aquí la solución completa del primer problema. Voilá:
POKE 84,V POKE 86,INT(H/256) POKE 85,H -256 * INT(H/256)Y escribimos esas dos últimas líneas en orden "inverso" para poder ofrecer una última línea sustituta, que no se explicará aquí, pero que debería quedar clara en unos pocos párrafos:
POKE 85,H - 256 * PEEK(86)¡Uf! ¡Todo eso para resolver solo el primer problema! ¡Anímese, es cada vez más fácil! De hecho, ya mencionamos que se puede recuperar la fila actual mediante "PEEK(84)". ¿Pero qué hay de la columna? Nuevamente, debemos recordar que el número de columna podría ser lo suficientemente grande como para requerir 2 bytes adyacentes (ubicaciones, celdas de memoria, etc.). Podríamos construir el número mayor mediante lo siguiente:
H2 = PEEK(85) H1 = PEEK(86) H = H2 + 256 * H1¿Ve la relación entre esto y los POKEs? Para recomponerlo, debemos multiplicar el byte de mayor orden por 256 (porque, recuerde, es la cantidad de 256 que podríamos obtener del número mayor) antes de sumarlo al byte de menor orden.
De nuevo, volvamos a sumar y simplifiquemos. El siguiente código satisfará para BASIC el segundo requisito del problema :
V = PEEK(84) H = PEEK(85) + 256 * PEEK(86)Bien. Lo logramos. Para dos lenguajes. Y si solo le interesa BASIC, puedes retirarse. Pero si tiene un poquito de curiosidad, quédese con nosotros. Esto se pone mejor.
BASIC A+
Puede que por mi parte tenga algo de prejuicio, pero creo que este es el lenguaje más fácil de explicar a los principiantes. De hecho, en lugar de empezar con el texto, mostremos las soluciones:
Problema 1. POKE 84,V DPOKE 85,H Problema 2. V = PEEK(84) H = DPEEK(85)
Como puede ver, para las situaciones de una sola celda de memoria, BASIC A+ funciona exactamente igual que los BASIC de Atari y Microsoft. Pero para los problemas de doble byte, BASIC A+ tiene una declaración y una función extra, diseñadas específicamente para interactuar con las "palabras" de doble byte del procesador 6502 del Atari.
DPOKE (Double POKE) realiza exactamente el mismo trabajo que los dos POKE requeridos por Atari BASIC. DPEEK (Double PEEK) combina de forma similar las funciones de ambos PEEK del Atari BASIC. Y listo. Simple y directo.
Forth
Creo que la facilidad para resolver los problemas requeridos en Forth demostrará la estrecha y precisa conexión entre Forth y el nivel de máquina del computador. De hecho, no tenemos que "inventar" una forma de resolver estos problemas; las soluciones se ajustan a las especificaciones, expectativas y capacidades habituales de prácticamente todas las implementaciones de Forth.
Nuevamente creo que mostraré las soluciones antes de explicar:
Problema 1. V@84c! H@85! Problema 2. 84 c@H! 85@V!Si no es usuario de Forth, todo esto puede parecer un poco críptico (a mí me parece un código secreto), pero tradúzcamoslo al pseudoinglés. La primera línea del primer problema podría leerse así:
V significa la ubicación (o variable) llamada "V" @ significa obtener el contenido de esa ubicación 84 significa usar el número 84 c! significa almacenar el carácter (byte) que obtuvimos primero, en la ubicación que obtuvimos en segundo lugar o, en forma más corta, "V se obtendrá como dato y 84 se utilizará como dirección de un celda de memoria del tamaño de un byte."
La segunda línea, entonces, se leería esencialmente igual excepto que el "!" usado (en lugar de "c!") implica un almacenamiento de palabras completas (doble byte), como lo hace DPOKE en BASIC A+.
La similitud y simetría de las soluciones de los problemas 1 y 2 son sorprendentes. Leamos la primera línea del segundo problema:
84 significa usar el número 84 (en este caso, como ubicación) c@ significa obtener el byte (carácter) en esa ubicación V significa obtener la ubicación (variable) llamada "V" ! significa almacenar los datos obtenidos primero, en la ubicación obtenida en segundo lugarY, de nuevo, la única diferencia entre esta y la siguiente línea es que "@" (en lugar de "c@") implica una búsqueda de doble byte (de nuevo, tal como lo hace DPEEK de BASIC A+).
No hay espacio aquí ni es apropiado ahora discutir las debilidades de la notación polaca inversa de Forth y su mecanismo de apilamiento, pero incluso los fanáticos más empedernidos del lenguaje algorítmico (como yo) pueden apreciar sus ventajas en situaciones como las que se demuestran aquí.
C
No, eso no significa "Sección C". Aunque parezca increíble, "C" es el nombre de un lenguaje de programación. De hecho, es uno de los lenguajes de programación más populares entre los programadores de sistemas. Es "el" lenguaje utilizado en y por el Sistema Operativo UNIX, que parece tener una gran ventaja para reemplazar a CP/M en las microcomputadoras más grandes (por ejemplo, las basadas en el 68000 y otros procesadores más avanzados).
C, al igual que Forth, está íntimamente ligado al nivel de la máquina. Por ejemplo, existen operadores en C que incrementan o decrementan una ubicación de memoria, al igual que existen instrucciones similares en el lenguaje ensamblador de la mayoría de los microprocesadores modernos.
Sin embargo, a diferencia de Forth, C requiere que el usuario declare que va más allá del alcance de las estructuras del lenguaje para acceder directamente al nivel de máquina. En C estándar (es decir, el de UNIX), podríamos cambiar la fila actual del cursor mediante algo como esto:
*((carácter *) 84) = V;Lo cual, supongo, es tan críptico como Forth para los no iniciados. Si recuerdan que los paréntesis implican precedencia, al igual que en BASIC, podrían interpretar lo anterior como "Usar la expresión '84' como puntero a un carácter (es decir, la dirección de un byte, especificada por 'char*') y almacenar V ('=') indirectamente (el primer '*') en esa ubicación". ¡Uf! Incluso los usuarios experimentados de C (bueno, algunos de nosotros) a menudo nos encontramos añadiendo paréntesis adicionales para asegurarnos de que la expresión signifique lo que queremos.
En fin, ese '(char *)' se llama "conversión de tipos" y es una característica de compiladores de C más avanzados que los disponibles para Atari. Pero, siendo justos, es una forma bastante deficiente de hacerlo. Así que hagámoslo "bien":
Problema 1. char *pc; /* pc es un puntero a un byte */ int *pi; /* pi es un puntero a un byte doble */ pc = 84; pi = 85; ... *pc = V; *pi = H; Problema 2. char *pc; int *pi; pc = 84; pi = 85; ... V = *pc; H = *pi;Al igual que con las soluciones de Pascal, en la siguiente sección debemos declarar el "tipo" de una variable, en lugar de simplemente asumir su existencia (como en BASIC) o declararla (como en Forth). En teoría, esto permitirá al compilador detectar más errores lógicos, ya que no se debe actuar incorrectamente con el tipo de variable incorrecto. (En la práctica, los compiladores de C disponibles para Atari, incluido nuestro propio C/65, son lo suficientemente flexibles como para permitir hacer trampa la mayor parte del tiempo).
Aquí, las declaraciones establecen que "pc" (contador de programa) siempre apuntará a (es decir, contendrá la dirección de) un elemento de tamaño byte. Pero "pi" siempre apuntará a un elemento de tamaño palabra (doble byte). Ahora bien, en realidad, estas variables no apuntan a nada hasta que les asignamos una dirección, lo cual hacemos mediante "pc = 84" y "pi = 85".
Y, finalmente, las asignaciones reales a o desde memoria se gestionan en la última línea de cada solución del problema. Ahora bien, todo esto parece muy complicado y poco útil, pero la ventaja de C es que, una vez que hemos hecho todas nuestras declaraciones, podemos usar las variables y estructuras dondequiera que las necesitemos en un módulo de programa, seguros de saber que nuestro código está al menos parcialmente autodocumentado.
Pascal
En realidad, el Pascal estándar no dispone de ningún método para resolver estos problemas. Recuerde que Pascal es un lenguaje "escolar", y el acceso a nivel de máquina no era una característica deseable en un entorno así. De hecho, la mayoría de los compiladores de Pascal actuales han inventado alguna forma de sortear las restricciones del Pascal "estándar", y es en gran medida debido a estas "invenciones" que las distintas versiones del lenguaje son incompatibles.
En cualquier caso, Atari Pascal proporciona un método para acceder a celdas de memoria individuales. No estoy seguro de que el método que mostraré aquí sea el mejor ni el más sencillo, pero parece funcionar. De nuevo, la solución se presenta primero:
Nota: el código de esta primera parte es común a ambos problemas, tanto para H como para V. (*en la sección de declaraciones "type"*) charaddr = record row : char; end; wordaddr = record col : integer; end; (*en la sección de declaraciones "var"*) pc : ^charaddr; pw : ^wordaddr; rowcrs : absolute [84] ^charaddr; colcrs : absolute [85] ^wordaddr; Problema 1. (incluye el código común anterior) (*código de ejecución en el procedimiento*) pc : = rowcrs; pw : = colcrs; pc^.row := V; pw^.col := H; Problema 2. (incluye el código común anterior) (*de nuevo, código de ejecución del procedimiento*) pc := rowcrs; pw := colcrs; V := Pc^.row; H := pw^.col;¿Se perdió? No se preocupe. Pensé que esto podría escribirse de forma más sencilla, pero quería presentar una versión que, con bastante seguridad, funcione en la mayoría de los casos.
Las declaraciones de tipo son necesarias simplemente para establecer formatos de registro a los que se pueda apuntar (y eran estos formatos de registro los que me parecían redundantes). Luego se declaran las variables que efectivamente apuntan a estos formatos de registro. Y lo más importante, el tipo "absoluto" nos permite informar al compilador de Pascal de que tenemos una constante que realmente es (de verdad, de verdad, por favor, que así sea) la dirección de uno de esos formatos de registro a los que queríamos apuntar. (Y es este tipo "absoluto" la extensión de Pascal que no está en el estándar).
Una vez realizadas todas las declaraciones, el código se parece sorprendentemente al código de C: asignamos la dirección absoluta al puntero y luego obtenemos o almacenamos mediante él. La sobrecarga de la referencia al elemento de registro (los ".row" y ".col") es la única diferencia real (y quizás innecesaria, como ya comenté).
PILOT
Y aquí llegamos, por fin, al lenguaje más simple de Atari. De nuevo, el PILOT estándar no tiene una forma definida de acceder a las celdas de memoria individuales. Y, de nuevo, la razón es que PILOT fue (y es) un lenguaje diseñado para su uso en escuelas, donde lo último que se quiere es hurgar en la memoria y colapsar el disco de 100 megabytes con el presupuesto del año siguiente.
Sin embargo, al usar PILOT en un computador Atari, lo peor que se puede hacer es procesar su propia copia de su propio disco o cassette. Por ello, Atari ha proporcionado, con gran cuidado, una forma de acceder a las celdas de memoria desde PILOT; y lo han hecho de una forma que recuerda notablemente a BASIC. Una vez más, la solución se da primero:
Problema 1. C:@B84 = #V C:@B86 = #H/256 C:@B85 = #H\256 Problema 2. C:#V = @B84 C:#H = @B85 + (256 * @B86)El truco reside en que Atari PILOT utiliza el operador "@B" para indicar una referencia a memoria. Cuando se usa a la izquierda del signo igual en una instrucción C: (compute), implica un almacenamiento (al igual que POKE en BASIC). Cuando se usa a la derecha del signo igual (o, por cierto, en pruebas Jump, etc.), implica una búsqueda de memoria (al igual que PEEK en BASIC).
Si ya ha examinado el código BASIC, probablemente notará una marcada similitud entre él y este ejemplo de PILOT. De nuevo, debemos descomponer el número mayor en sus dos componentes: el número de unidades de 256 (#H/256) y el resto. Observe que con PILOT no necesitamos (ni podemos) especificar "INT(#H/256)". No existe la función INT simplemente porque toda la aritmética en Atari PILOT ya se realiza con enteros de doble byte. A veces, como en este caso, esto puede ser una ventaja. En otras ocasiones, la falta del punto flotante impedirá el uso de PILOT en diversas aplicaciones.
Observe la última línea de la solución al problema 1: el uso del operador "\" (módulo) es, en esencia, una abreviatura práctica disponible en varios lenguajes. En PILOT,
"#H\256"es exactamente equivalente a
"#H - (256 * (#H/256) )".Atari PILOT es mucho más flexible y usable que el original, así que ¿por qué no aprovechar todas sus funciones? Experimente. Se alegrará de haberlo hecho.
Ensamblador y Lenguaje de Máquina
Casi no incluí esta sección, ya que cualquiera que trabaje con lenguaje ensamblador (y especialmente quienes intenten depurar a nivel de lenguaje de máquina) presumiblemente sabrá cómo manipular bytes y palabras. Sin embargo, podría resultar interesante para quienes no conocen ensamblador ver cómo el procesador 6502 realmente realiza sus funciones. Para las soluciones de ejemplo, asumiremos que en algún lugar de nuestro programa hemos codificado algo equivalente a lo siguiente:
V * = * + 1 ; reserva 1 byte para V H * = * + 2 ; reserva 2 bytes para HEstas líneas no asignan valores a V y H; simplemente asignan espacio de memoria para almacenar los valores finales (algo así como la mención de un arreglo en Atari BASIC, que no asigna ningún valor específico al arreglo). Si quisiéramos no solo reservar espacio para las "variables" V y H, sino también asignarles un valor inicial, podríamos codificar esto:
V .BYTE 3 ; asigna el valor inicial de 3 al byte V H .WORD 290 ; asigna el valor inicial de 290 a la palabra HDe todos modos, dado que H y V se han reservado y se les ha asignado algún valor, aquí están las soluciones a los problemas:
Problema 1. LDA V ; obtenemos el contenido de V STA 84; y lo almacenamos en ROWCRS LDA H ; luego obtenemos el primer byte de H STA 85; y lo almacenamos en el primer byte de COLCRS LDA H + 1 ; ¿qué es esto? ¡el segundo byte de H! STA 86 ; en el segundo byte de COLCRS Problema 2. LDA 84 ;casi no hace falta comentar esto... STA V; ¡es solo el problema 1 al revés! LDA 85; primer byte de COLCRS nuevamente STA H ; en el byte menos significativo de H LDA 86; y también el segundo byte STA H + 1; el byte de orden alto de H¿Se pregunta por qué no intentamos mover ambos bytes de H a la vez, tal como lo hicimos en BASIC A+, arriba? Sencillo: ¡el microprocesador 6502 no puede mover dos bytes en una sola instrucción! ¡En serio! (Y este es probablemente su mayor defecto como CPU). Claro que, si tiene un ensamblador de macros, podría escribir una macro para realizar estas operaciones. Aquí tienes un ejemplo con un ensamblador de macros disponible para Atari, aunque todos los ensambladores de macros funcionan al menos de forma similar. Primero, definimos un par de macros:
.MACRO MOVEWORD LDA %1 STA %2 LDA %1+1 STA %2+1 .ENDM .MACRO MOVEBYTE LDA %1 STA %2 .ENDMAmbas macros simplemente mueven su primer "argumento" a su segundo "argumento" (y no definiremos aquí qué son los "argumentos" ni cómo funcionan (consulte el manual del ensamblador de macros para obtener más información). La primera macro mueve dos bytes adyacentes (es decir, una palabra), y la segunda mueve un solo byte. Ahora podemos escribir el código de nuestro problema de forma mucho más sencilla:
Problema 1. MOVEBYTE V,84 MOVEWORD H,85 Problema 2. MOVEBYTE 84,V MOVEWORD 85,HY otro concepto más antes de dejar el lenguaje ensamblador. Una de las características más potentes de un ensamblador es su capacidad para manejar equivalencias de símbolos (equates). La verdadera ventaja de esto, además de producir un código más legible, es que se pueden cambiar todas las referencias a una ubicación, valor o lo que sea con solo modificar una equivalencia en el código fuente. Por lo tanto, si cerca del comienzo de nuestro programa fuente hubiéramos codificado las siguientes 2 líneas:
ROWCRS = 84; dirección del cursor ROW COLCRS = 85; dirección del cursor de columnaEntonces podríamos haber "resuelto" los problemas así:
Problema 1. MOVEBYTE V, ROWCRS MOVEWORD H,COLCRS Problema 2. MOVEBYTE ROWCRS,V MOVEWORD COLCRS,H¡Y creo que esto se ve tan elegante y legible como cualquier lenguaje de alto nivel! De hecho, se ve más legible que la mayoría de los ejemplos anteriores. Para ser justos, cabe destacar que todos los ejemplos podrían haber sido más legibles sustituyendo los nombres de las variables en lugar de los números absolutos "84" y "85", pero la sobrecarga de declarar y asignar variables a veces no compensa en lenguajes como BASIC y PILOT.
Por suerte, el resto de los lenguajes (Forth, C y Pascal) tienen un método para declarar constantes (similar a las equivalencias del lenguaje ensamblador) que tiene poca o ninguna sobrecarga. Así que adelante, sea el bicho raro de su barrio y haga que su código sea legible y fácil de mantener. Puede que pierda amigos, pero podría ayudarle a conseguir trabajo.
Feliz Mapeo
Bueno, lo logramos. Espero que ahora al menos tenga una idea de qué hacer para modificar y examinar diversas ubicaciones de memoria en todos los lenguajes mostrados. Prácticamente todas las ubicaciones mapeadas en este libro se clasificarán en una de las dos categorías examinadas: implicarán cambiar o examinar un byte simple o uno doble (palabra, entero, dirección, etc.). Si siguen los modelos que se muestran aquí, no tendrá problemas para lograr sus objetivos.
Para las pocas ubicaciones que no siguen los patrones anteriores (por ejemplo, el reloj del sistema, que es una ubicación de tres bytes en orden alto-medio-bajo), podría lograr sus objetivos considerando cada byte individualmente. Además, no hemos abordado aquí el formato de punto flotante del Atari, que solo es accesible de forma razonable desde el lenguaje ensamblador, y que, en cualquier caso, tiene poca relevancia para este mapa de memoria.
Creo que me gustaría añadir solo un comentario más, a modo de advertencia: si no está seguro de lo que hace al cambiar o examinar las ubicaciones de memoria, asegúrese de tener una copia de seguridad de su programa en memoria (en disco o cassette) y luego asegúrese de haber extraído los discos o cintas. Es poco probable que cambiar la memoria cause problemas que afecten a los archivos guardados, pero ¿para qué arriesgarse? (Y, si comete un error o tiene dudas, reinicie el disco; no presione simplemente RESET, ya que eso no necesariamente eliminará todos los errores).
¡Mucha suerte y que disfrute su mapeo!