Capítulo 1 - Introducción al lenguaje ensamblador

¡Comience a programar de inmediato en lenguaje de máquina! Encienda su computador Atari y digite el siguiente programa. A continuación, ejecútelo, y escriba algunas palabras. Verá algo muy interesante en la pantalla de su computador.


PROGRAMA DE EJEMPLO N° 1
"D:PATASARR.BAS"

10 REM ** "D:PATASARR.BAS" **
20 REM ** UN PROGRAMA EN LENGUAJE DE MAQUINA **
30 REM ** QUE PUEDES EJECUTAR **
40 REM ** PATAS ARRIBA **
50 REM
60 GRAPHICS 0 : PRINT
100 POKE 755, 4
110 OPEN #1,4,0,"K:"
120 GET #1,K
130 PRINT CHR$(K);
140 GOTO 120


Captura de la pantalla

Por supuesto, este es un programa en BASIC. La línea 60 limpia la pantalla de su computador por medio del comando GRAPHICS 0. La línea 110 abre el teclado de su Atari como dispositivo de entrada. Luego, de las líneas 120 a la 140, hay un ciclo que imprime en la pantalla los caracteres que se han digitado. Pero la línea más importante de este programa, es la línea 100. El ingrediente activo de la línea 100, la instrucción POKE 755,4, es en realidad una instrucción de lenguaje de máquina. De hecho, todos los comandos POKE en BASIC son instrucciones en lenguaje de máquina. Cuando se utiliza un comando POKE en BASIC, lo que usted está haciendo es almacenar un número en una posición de memoria específica de su computador. Y cuando se almacena un número en una posición de memoria específica de su computador, lo que está haciendo es usar lenguaje de máquina.


Bajo el capó de su Atari


Cada computador tiene tres partes principales: una unidad de procesamiento central (Central Processing Unit – CPU), la memoria (por lo general dividida en dos bloques llamados memoria de acceso aleatorio (Random Access Memory – RAM) y memoria de sólo lectura (Read Only Memory – ROM), y los dispositivos de entrada / salida – E/S (Input/Output – I/O).


Principales partes del computador hogareño Atari

El dispositivo de entrada principal de su Atari es el teclado. Su dispositivo de salida principal es su monitor de video. Otros dispositivos de E/S a los que se puede conectar un computador Atari son los módems telefónicos, tableros gráficos, grabadores de cassettes, y unidades de disco. En un microcomputador, todas las funciones de una unidad central de procesamiento están contenidas en una Unidad de Microprocesador o MPU (MicroProcessor Unit).La MPU de su computador Atari, así como su Unidad Central de Proceso (Central Processing Unit – CPU), es un circuito a Gran Escala de Integración (Large Scale Integration – LSI) llamado microprocesador 6502.


La Familia 6502


El microprocesador 6502, centro de mando de su equipo, fue desarrollado por MOS Technology, Inc. Varias compañías ahora poseen la licencia para la fabricación de chips 6502, y algunos fabricantes de computadores lo usan en sus máquinas. El chip 6502 y varios modelos actualizados, tales como el 6502A y el 6510, no sólo son utilizados en los computadores Atari, sino también en los computadores personales fabricados por Apple, Commodore, y Ohio Scientific.


Eso significa, por supuesto, que el lenguaje ensamblador 6502 también se puede utilizar para programar diferentes computadores personales – incluyendo el Apple II, Apple II +, Apple e y Apple /, todos los computadores de Ohio Scientific, el computador Commodore PET, y el Commodore 64.


Y eso no es todo; los principios utilizados en el lenguaje de programación ensamblador de Atari son universales; son los mismos principios que usan los programadores en lenguaje ensamblador, sin importar para qué tipo de computador están escribiendo sus programas.


Una vez que aprenda el lenguaje ensamblador 6502, le será fácil aprender a programar otro tipo de procesador, como el chip Z-80 usado en computadores Radio Shack y equipos basados en CP/M, e incluso los chips poderosos más nuevos que se utilizan en micro-computadores de 16-bits, como el IBM-PC.


Las Fuentes de ROM


Su equipo tiene dos tipos de memoria: Memoria de Acceso Aleatorio (RAM) y Memoria de Sólo Lectura (ROM). ROM es la memoria a largo plazo de su Atari. Fue instalada en su equipo en la fábrica, y es tan permanente como su teclado. La ROM de su equipo está permanentemente grabada en un grupo determinado de chips, así que nunca se borra, incluso cuando se apaga el suministro de corriente. Para los dueños de la mayoría de los equipos hogareños, esto es algo bueno.


Sin su ROM, su Atari no sería un Atari. De hecho, no sería mucho más que un carísimo pisapapeles de alta tecnología. El mayor bloque de memoria en la ROM es el bloque que contiene el Sistema Operativo (Operating System – OS) de su computador. El sistema operativo de su Atari es lo que le permite hacer todas esas cosas maravillosas que se supone que los Ataris tienen que hacer, como permitir el ingreso de datos desde el teclado, desplegar caracteres en la pantalla, etc.


También la ROM es lo que permite a su equipo comunicarse con dispositivos periféricos como discos duros, grabadoras de cassettes, y módems telefónicos. Si usted es dueño de un computador Atari de la serie XL, el paquete ROM de su unidad también contiene una serie de características adicionales, como un sistema de auto-diagnóstico, un conjunto de caracteres de idiomas extranjeros, y lenguaje BASIC incorporados.


La RAM es volátil


La ROM, como puede imaginar, no se construyó en un día. El paquete ROM de su Atari es el resultado de un montón de trabajo en lenguaje ensamblador hecho por una gran cantidad de programadores. El contenido de la RAM, por otra parte, puede ser escrito por cualquier persona – incluso usted. La memoria RAM es la memoria principal del computador. Tiene muchas más celdas de memoria que la ROM, pero la RAM, a diferencia de la ROM, es volátil.


El problema con la RAM es que se puede borrar, o, como diría un ingeniero informático, es volátil. Cuando usted enciende su computador, el bloque de memoria en su interior que está reservado para la RAM está tan vacío como una hoja de papel en blanco.


Y cuando usted apaga su equipo, desaparece cualquier cosa que usted pueda tener en la memoria RAM. Es por eso que la mayoría de los programas de computadores tienen que ser cargados en la memoria RAM desde de los dispositivos de almacenamiento masivo, tales como grabadoras de cassettes y unidades de disco. Después de haber escrito un programa, usted tiene que guardarlo en algún lugar para que no se borre cuando se desconecte la corriente y se borre la memoria RAM.


La memoria RAM de su computador, o memoria principal, se puede imaginar como una red enorme formada por miles de compartimentos, o celdas, algo así como filas sobre filas de casillas de correos a lo largo de una pared. Cada celda de esta gran matriz de memoria se llama posición de memoria, y cada posición de memoria, como cada casilla en una oficina de correos, tiene una dirección de memoria individual y única.


La analogía entre los computadores y las casillas de correos no termina allí. Un programa, como un trabajador postal experto que pone cartas en las casillas de la oficina de correos, puede llegar rápidamente a cualquier posición de memoria. En otras palabras, se puede acceder a cualquier posición en su memoria al azar. Y es por eso que a la memoria de un computador que es direccionable por el usuario se le conoce como memoria de acceso aleatorio.


Las "Cartas" son Números


Sin embargo, nuestra analogía de la oficina de correos no es absolutamente perfecta. Una casilla de la oficina de correos puede llenarse con muchas cartas, pero cada posición de memoria de un computador sólo puede tener un solo número. Y ese número puede representar sólo una de tres cosas:


  • El número almacenado en sí;
  • Un código que representa un carácter, o 
  • Una instrucción de lenguaje de máquina.

¿Qué viene a continuación?


Cuando un computador se dirige a una posición de memoria y encuentra un número, se le debe decir qué hacer con el número que encontró. Si el número equivale a un simple número, entonces se le debe decir al computador por qué el número está ahí. Si el número es un código que representa un carácter, a continuación, se le debe decir al computador cómo se va a utilizar ese carácter. Y si el número debe ser interpretado como una instrucción de lenguaje de máquina, también se le debe decir al computador que se trata de una instrucción de lenguaje de máquina.


Las instrucciones son programas


Las instrucciones que se le dan a las computadores para que puedan encontrar e interpretar los números almacenados en la memoria se denominan programas de computador. La gente que escribe programas son, por supuesto, programadores. Los lenguajes en que los programas están escritos se llaman lenguajes de programación. De todos los lenguajes de programación, el ensamblador es el más global.


Ejecutando un programa en Lenguaje de Máquina


Cuando su computador va a ejecutar un programa, lo primero que se le tiene que decir es en qué lugar de su memoria está almacenado el programa. Una vez que tenga dicha información, podrá ir a la dirección de memoria donde comienza el programa y echar un vistazo a lo que hay allí.


Si el equipo encuentra una instrucción que está programado para entender, entonces ejecutará dicha instrucción. El computador pasará a la siguiente dirección en su memoria. Después de seguir las instrucciones que encuentre allí, se pasará a la siguiente dirección, y así sucesivamente.


El equipo repetirá este proceso de ejecutar una instrucción y pasar a la siguiente, hasta que llega al final de cualquier programa que se ha almacenado en su memoria. Entonces, a menos que encuentre una instrucción para regresar a una dirección en el programa o para saltar a una nueva dirección, simplemente se queda, esperando pacientemente recibir otra instrucción.


Lenguajes de Computadores


Como ustedes saben, los programas pueden ser escritos en decenas de lenguajes de programación tales como BASIC, COBOL, Pascal, LOGO, etc. Lenguajes como éstos son llamados lenguajes de alto nivel, no porque sean especialmente esotéricos o profundos, sino porque están escritos en un nivel demasiado alto para que un computador lo pueda entender.


Un computador puede entender sólo un lenguaje, el lenguaje de máquina, el cual está escrito totalmente en números. Así que antes de que un computador pueda ejecutar un programa escrito en un lenguaje de alto nivel, el programa de alguna manera debe ser traducido a lenguaje de máquina.


Los programas escritos en lenguajes de alto nivel usualmente son traducidos a lenguaje de máquina por medio del uso de paquetes de software llamados intérpretes y compiladores. Un intérprete es un software que puede convertir un programa a lenguaje de máquina, a medida que éste está siendo escrito.


El intérprete BASIC de su Atari es un intérprete de lenguaje de alto nivel. Los intérpretes se usan para convertir programas escritos en otros lenguajes de alto nivel, como LOGO y Pilot, en programas de lenguaje de máquina. Un compilador es un paquete de software diseñado para convertir los lenguajes de alto nivel en lenguaje de máquina después de que éstos se hayan escrito. COBOL, Pascal y la mayoría de los lenguajes de alto nivel se suelen traducir a lenguaje de máquina con la ayuda de los compiladores.


Ensambladores de Lenguaje de Máquina


Los intérpretes y compiladores no se utilizan en la escritura de programas en lenguaje ensamblador. Los programas de lenguaje de máquina casi siempre son escritos con la ayuda de paquetes de software llamados ensambladores.


Existen otros ensambladores para el computador Atari, tales como el paquete avanzado Atari Macro Assembler y Atari Program-Text Editor de Atari. Un ensamblador no funciona como un intérprete, o como un compilador. Esto es porque el lenguaje ensamblador no es un lenguaje de alto nivel. En efecto, se podría decir que el lenguaje ensamblador no es realmente un lenguaje de programación.


En realidad, el lenguaje ensamblador no es más que un sistema de notación utilizado para escribir programas en lenguaje de máquina utilizando símbolos alfabéticos que los programadores humanos pueden entender.
Lo que estamos tratando de hacer entender aquí es el hecho de que el lenguaje ensamblador es totalmente diferente de cualquier otro lenguaje de programación. Cuando un programa en lenguaje de alto nivel es traducido a lenguaje de máquina por un intérprete o compilador, una sola instrucción en el lenguaje original fácilmente puede equivaler a decenas – a veces incluso centenares – de instrucciones de lenguaje de máquina. Sin embargo, cuando se escribe un programa en lenguaje ensamblador, cada instrucción que es usada en el lenguaje ensamblador equivale a una sola instrucción de lenguaje de máquina con exactamente el mismo significado. En otras palabras, hay una relación exacta de uno a uno entre la instrucción en lenguaje ensamblador y las instrucciones en lenguaje máquina. Debido a esta correspondencia única, los ensambladores de lenguaje de máquina tienen un trabajo mucho más fácil que el que realizan los intérpretes y compiladores.


Dado que los programas en lenguaje ensamblador (a menudo llamado el código fuente) se pueden convertir directamente en programas de lenguaje de máquina (a menudo conocido como código objeto), un ensamblador puede simplemente pasar como un rayo traduciendo listados de código fuente en código objeto, sin tener que luchar con todas las tortuosas contorsiones de traducción que los intérpretes tienen que enfrentar cada vez que llevan a cabo sus tareas.


Los ensambladores también tienen una ventaja sobre los compiladores. Los programas que producen tienden a ser más sencillos y menos repetitivos. Los programas ensamblados son más eficientes con la memoria y corren más rápido que los programas interpretados o compilados.


La difícil situación del Programador


Desafortunadamente, se debe pagar un precio por toda esta eficiencia y velocidad; y el individuo que paga este precio es, tristemente, el programador en lenguaje ensamblador. Irónicamente, a pesar de que los programas en lenguaje ensamblador funcionarán mucho más rápido que los programas escritos en lenguaje de alto nivel, estos requieren de muchas más instrucciones y toman mucho más tiempo en ser escritos.


Una estimación ampliamente citada es que a un programador experto le toma cerca de diez veces más tiempo el escribir un programa en lenguaje ensamblador que lo que le tomaría escribir el mismo programa en un lenguaje de alto nivel como BASIC, COBOL, o Pascal. Por otra parte, los programas en lenguaje ensamblador se ejecutan 10 a 1000 veces más rápido que los programas en BASIC, y pueden hacer cosas que los programas en BASIC no pueden hacer a ninguna velocidad. Así que si quiere convertirse en un programador experto, realmente no tiene más remedio que aprender el lenguaje ensamblador.


Cómo funciona el Lenguaje de Máquina


El lenguaje de máquina, como cualquier otro lenguaje de computadores, se compone de instrucciones. Sin embargo, como hemos señalado, cada instrucción que se usa en lenguaje de máquina es un número. Los números que entienden los computadores no son del tipo que estamos acostumbrados a usar. Los computadores piensan en números binarios – números que no son más que secuencias de unos y ceros. Aquí tenemos, por ejemplo, una parte de un programa de computador escrito en números binarios (el tipo de números que un computador entiende):

00011000
11011000
10101001
00000010
01101001
00000010
10000101
11001011
01100000

No hace falta mucha imaginación para ver que usted estaría en un problema si tiene que escribir programas extensos, en el estilo binario del lenguaje de máquina que normalmente contienen miles de instrucciones. Con un ensamblador, sin embargo, la tarea de escribir un programa en lenguaje de máquina es considerablemente más fácil. Aquí, por ejemplo, está el programa anterior, tal como aparecería si usted lo hubiera escrito en lenguaje ensamblador:

CLC
CLD
LDA 02
ADC 02
STA $CB
RTS

Puede no entender todo eso todavía, pero tendrá que admitir que por lo menos se ve más comprensible. Lo que hace el programa, por cierto, es sumar 2 y 2. Luego se almacena el resultado del cálculo en una ubicación de memoria determinada de su computador – en concreto, la dirección de memoria 203. Más adelante volveremos a este programa y le daremos una mirada más en detalle. Entonces tendrá la oportunidad de ver exactamente cómo funciona. Antes, eso sí, vamos a enfocarnos en los ensambladores y el lenguaje ensamblador.


Comparación entre Lenguaje Ensamblador y BASIC


Los programas en lenguaje ensamblador se escriben usando instrucciones de tres letras llamadas mnemotécnicos. Algunos mnemotécnicos son similares a instrucciones BASIC. Una instrucción en lenguaje ensamblador que es muy similar a una instrucción BASIC es RTS, la última instrucción en la rutina de ejemplo que acabamos de revisar. RTS (0110 0000 escrito en lenguaje de máquina) significa "regrese de la subrutina" ("ReTurn from Subroutine.").


Se utiliza de manera similar a la instrucción RETURN de BASIC. También hay un mnemotécnico del lenguaje ensamblador que es similar a la instrucción GOSUB de BASIC. Se escribe JSR, y significa salte a la subrutina ("Jump to SuBroutine."). Su equivalente en código binario de lenguaje de máquina es 0010 000.


Sin embargo, no todas las instrucciones en lenguaje ensamblador tienen tal parecido con las instrucciones del BASIC. Una instrucción en lenguaje ensamblador nunca le ordena al computador ejecutar algo tan complejo como dibujar una línea o imprimir una letra en la pantalla, por ejemplo.


En cambio, la mayoría de los mnemónicos del lenguaje ensamblador ordenan a los computadores ejecutar tareas muy elementales como la suma de dos números, comparar dos datos, o (como hemos visto) saltar a una subrutina. Es por eso que a veces se requiere un gran número de instrucciones de lenguaje ensamblador para igualar a una o dos instrucciones en un lenguaje de alto nivel.


Código Fuente y Código Objeto


Cuando escribe un programa en lenguaje ensamblador, el listado que usted produce se llama código fuente, ya que es la fuente de la que un programa de lenguaje de máquina será producido. Una vez que ha escrito el código fuente de un programa en lenguaje ensamblador, puede pasarlo por un ensamblador. El ensamblador lo convertirá en un código objeto, que es sólo otro nombre para un programa en lenguaje de máquina producido por un ensamblador.


La Velocidad y Eficiencia del Lenguaje de Máquina


Dado que las instrucciones en lenguaje ensamblador son tan específicas (incluso podríamos decir primitivas), obviamente toma muchas de ellas el hacer un programa completo, y muchas, muchas más instrucciones de lo que tomaría escribir el mismo programa en un lenguaje de alto nivel.


Irónicamente, los programas en lenguaje de máquina aún ocupan menos espacio en memoria que los programas escritos en lenguajes de alto nivel. Esto es porque cuando un programa escrito en un lenguaje de alto nivel es interpretado o compilado en lenguaje de máquina, grandes bloques de código de máquina deben ser repetidos cada vez que se utilizan. Pero en un buen programa escrito en lenguaje ensamblador, una rutina que se utiliza una y otra vez puede ser escrita sólo una vez, y luego será utilizada cuantas veces como sea necesario por medio de JSR, RTS, y otros comandos similares. Muchos otros tipos de técnicas pueden utilizarse para conservar la memoria en los programas escritos en lenguaje ensamblador.