- Importancia
- Ventajas y desventajas del Lenguaje Ensamblador
- Modos de direccionamiento
- Tabla de combinaciones posibles
Es importante como se puede ver, el Lenguaje Ensamblador es directamente traducible al Lenguaje de Máquina, y viceversa; simplemente, es una abstracción que facilita su uso para los seres humanos. Por otro lado, la computadora no entiende directamente al Lenguaje Ensamblador; es necesario traducirle a Lenguaje de Máquina. Pero, al ser tan directa la traducción, pronto aparecieron los programas Ensambladores, que son traductores que convierten el código fuente (en Lenguaje Ensamblador) a código objeto (es decir, a Lenguaje de Máquina. Surge como una necesidad de facilitar al programador la tarea de trabajar con lenguaje máquina sin perder el control directo con el hardware.
Ventajas y desventajas del Lenguaje Ensamblador
Una vez que hemos visto la evolución de los lenguajes, cabe preguntarse: ¿En estos tiempos "modernos", para qué quiero el Lenguaje Ensamblador?
El proceso de evolución trajo consigo algunas desventajas, que ahora veremos como las ventajas de usar el Lenguaje Ensamblador, respecto a un lenguaje de alto nivel:
Por otro lado, al ser un lenguaje más primitivo, el Ensamblador tiene ciertas desventajas respecto a los lenguajes de alto nivel:
- Tiempo de programación
- Programas fuente grandes
- Peligro de afectar recursos inesperadamente
- Falta de portabilidad
El proceso de traducción que realizan los intérpretes, implica un proceso de cómputo adicional al que el programador quiere realizar. Por ello, nos encontraremos con que un intérprete es siempre más lento que realizar la misma acción en Lenguaje Ensamblador, simplemente porque tiene el costo adicional de estar traduciendo el programa, cada vez que lo ejecutamos.
De ahí nacieron los compiladores, que son mucho más rápidos que los intérpretes, pues hacen la traducción una vez y dejan el código objeto, que ya es Lenguaje de Máquina, y se puede ejecutar muy rápidamente. Aunque el proceso de traducción es más complejo y costoso que el de ensamblar un programa, normalmente podemos despreciarlo, contra las ventajas de codificar el programa más rápidamente.
Sin embargo, la mayor parte de las veces, el código generado por un compilador es menos eficiente que el código equivalente que un programador escribiría. La razón es que el compilador no tiene tanta inteligencia, y requiere ser capaz de crear código genérico, que sirva tanto para un programa como para otro; en cambio, un programador humano puede aprovechar las características específicas del problema, reduciendo la generalidad pero al mismo tiempo, no desperdicia ninguna instrucción, no hace ningún proceso que no sea necesario.
Para darnos una idea, en una PC, y suponiendo que todos son buenos programadores, un programa para ordenar una lista tardará cerca de 20 veces más en Visual Basic (un intérprete), y 2 veces más en C (un compilador), que el equivalente en Ensamblador.
Por ello, cuando es crítica la velocidad del programa, Ensamblador se vuelve un candidato lógico como lenguaje.
Ahora bien, esto no es un absoluto; un programa bien hecho en C puede ser muchas veces más rápido que un programa mal hecho en Ensamblador; sigue siendo sumamente importante la elección apropiada de algoritmos y estructuras de datos. Por ello, se recomienda buscar optimizar primero estos aspectos, en el lenguaje que se desee, y solamente usar Ensamblador cuando se requiere más optimización y no se puede lograr por estos medios.
Por las mismas razones que vimos en el aspecto de velocidad, los compiladores e intérpretes generan más código máquina del necesario; por ello, el programa ejecutable crece. Así, cuando es importante reducir el tamaño del ejecutable, mejorando el uso de la memoria y teniendo también beneficios en velocidad, puede convenir usar el lenguaje Ensamblador. Entre los programas que es crítico el uso mínimo de memoria, tenemos a los virus y manejadores de dispositivos (drivers). Muchos de ellos, por supuesto, están escritos en lenguaje Ensamblador.
Las razones anteriores son cuestión de grado: podemos hacer las cosas en otro lenguaje, pero queremos hacerlas más eficientemente. Pero todos los lenguajes de alto nivel tienen limitantes en el control; al hacer abstracciones, limitan su propia capacidad. Es decir, existen tareas que la máquina puede hacer, pero que un lenguaje de alto nivel no permite. Por ejemplo, en Visual Basic no es posible cambiar la resolución del monitor a medio programa; es una limitante, impuesta por la abstracción del GUI Windows. En cambio, en ensamblador es sumamente sencillo, pues tenemos el acceso directo al hardware del monitor.
Al ser de bajo nivel, el Lenguaje Ensamblador requiere más instrucciones para realizar el mismo proceso, en comparación con un lenguaje de alto nivel. Por otro lado, requiere de más cuidado por parte del programador, pues es propenso a que los errores de lógica se reflejen más fuertemente en la ejecución.
Por todo esto, es más lento el desarrollo de programas comparables en Lenguaje Ensamblador que en un lenguaje de alto nivel, pues el programador goza de una menor abstracción.
Programas fuente grandes
Por las mismas razones que aumenta el tiempo, crecen los programas fuentes; simplemente, requerimos más instrucciones primitivas para describir procesos equivalentes. Esto es una desventaja porque dificulta el mantenimiento de los programas, y nuevamente reduce la productividad de los programadores.
Peligro de afectar recursos inesperadamente
Tenemos la ventaja de que todo lo que se puede hacer en la máquina, se puede hacer con el Lenguaje Ensamblador (flexibilidad). El problema es que todo error que podamos cometer, o todo riesgo que podamos tener, podemos tenerlo también en este Lenguaje. Dicho de otra forma, tener mucho poder es útil pero también es peligroso.
En la vida práctica, afortunadamente no ocurre mucho; sin embargo, al programar en este lenguaje verán que es mucho más común que la máquina se "cuelgue", "bloquee" o "se le vaya el avión"; y que se reinicialize. ¿Por qué?, porque con este lenguaje es perfectamente posible (y sencillo) realizar secuencias de instrucciones inválidas, que normalmente no aparecen al usar un lenguaje de alto nivel.
En ciertos casos extremos, puede llegarse a sobrescribir información del CMOS de la máquina (no he visto efectos más riesgosos); pero, si no la conservamos, esto puede causar que dejemos de "ver" el disco duro, junto con toda su información.
Como ya se mencionó, existe un lenguaje ensamblador para cada máquina; por ello, evidentemente no es una selección apropiada de lenguaje cuando deseamos codificar en una máquina y luego llevar los programas a otros sistemas operativos o modelos de computadoras. Si bien esto es un problema general a todos los lenguajes, es mucho más notorio en ensamblador: yo puedo reutilizar un 90% o más del código que desarrollo en "C", en una PC, al llevarlo a una RS/6000 con UNIX, y lo mismo si después lo llevo a una Macintosh, siempre y cuando esté bien hecho y siga los estándares de "C", y los principios de la programación estructurada. En cambio, si escribimos el programa en Ensamblador de la PC, por bien que lo desarrollemos y muchos estándares que sigamos, tendremos prácticamente que reescribir el 100 % del código al llevarlo a UNIX, y otra vez lo mismo al llevarlo a Mac.
Veamos ahora como se organizan y una breve descripción de los mismos:
Registro de 8 bits | R de 16 b al que pertenece | Descripción |
A | AF | Acumulador. El registro más usado J . |
F | AF | Flags. Indicadores de estado. |
B | BC | Normalmente usado como contador. |
C | BC | |
D | DE | |
E | DE | |
H | HL | HL es ideal para acceder a memoria J . |
L | HL | |
A’ | AF’ | A alternativo. |
F’ | AF’ | F alternativo. |
B’ | BC’ | B alternativo. |
C’ | BC’ | C alternativo. |
D’ | DE’ | D alternativo. |
E’ | DE’ | E alternativo. |
H’ | HL’ | H alternativo. |
L’ | HL’ | L alternativo. |
Xh | IX | IX vale para direccionamiento indexado. |
Xl | IX | |
Yh | IY | IY vale para direccionamiento indexado. |
Yl | IY | |
I | "IR" | Registro de interrupción. |
R | "IR" | Registro de refresco. |
PC | Contador del programa. | |
SP | Contador de la pila. |
A parte de esos, tiene otro dos que son boléanos (1 sólo bit), llamados iff0 y iff1 (y al menos otro registro interno de 8 bits para cálculos internos suyos).
Los registros con un <’> son alternativos. Digamos que están en el banquillo esperando que salga del juego su homólogo para entrar él. No se les puede acceder directamente (habría más jugadores de los reglamentarios), pero siempre se puede hacer el cambio (aquí son ilimitados). Siempre que se produce uno de éstos cambios, se intercambia un registro de 16 bits enterito. No vale cambiar sólo uno de 8.
Xh, Yh, Xl, Yl son los registros de 8 bits que conforman IX e IY. Oficialmente, las instrucciones que operan sobre ellos están indocumentadas, pero me parece una tontería el no hablar de ellos desde el principio.
PC contiene el "contador del programa", es decir, la dirección de memoria en la cual el procesador leerá su próxima instrucción
Se les llama modos de direccionamiento a las distintas formas de combinar los operadores según el acceso que se hace a memoria.
Dicho de otra manera, un modo de direccionamiento será una forma de parámetro para las instrucciones. Una instrucción que lleve un parámetro, por lo tanto, usará un modo de direccionamiento, que dependerá de cómo direccionará (accesará) al parámetro; una instrucción de dos parámetros, combinará dos modos de direccionamiento.
- Modo registro
Usa solamente registros como operadores
Es el más rápido, pues minimiza los recursos necesarios (toda la información fluye dentro del EU del CPU).
- Modo inmediato
Tiene dos operandos: un registro y una constante que se usa por su valor.
El valor constante no se tiene que buscar en memoria, pues ya se obtuvo al hacer el "fetch" de la instrucción.
Por tanto, es rápido aunque no tanto como el modo registro; requiere ir al BIU por el dato.
- Modo directo
Uno de los operandos involucra una localidad específica de memoria
El valor constante se tiene que buscar en memoria, en la localidad especificada.
Es más lento que los anteriores, pero es el más rápido para ir a memoria, pues ya "sabe" la localidad, la toma de la instrucción y no la tiene que calcular.
- Modo indirecto
Se usan los registros SI, DI como apuntadores
El operando indica una localidad de memoria, cuya dirección (sólo la parte desplazamiento) está en SI o DI.
Es más lento que los anteriores, pues tiene que "calcular" la localidad.
- Modo indexado de base
Formato:
[ BX o BP + SI o DI (opcionales) + constante (opcional) ]
BX o BP indica una localidad base de la memoria
A partir de BX o BP, se puede tener un desplazamiento variable y uno constante
La diferencia es el segmento sobre el que trabajan por defecto:
BX por defecto en el segmento de datos
BP por defecto en el segmento de pila.
Tabla de combinaciones posibles
De acuerdo a lo que se ha visto, y a la regla de que no se permiten dos accesos a memoria en la misma instrucción, se pueden combinar en la siguiente forma:
Modo destino | Modo Fuente | Registro | Inmediato | Directo | Indirecto | Indexado |
Registro | ||||||
Inmediato | No se puede tener inmediato a la izquierda (¿dónde se depositaría la información?) | |||||
Directo | Estas combinaciones no se pueden (serían dos accesos a memoria en la misma instrucción) | |||||
Indirecto | ||||||
Indexado |
Por favor envienos sugerencias nuestro correo electrónico:
Irma araceli pool cocom
Ana patricia chuc chable
Alma del Rosario Noh Pech
PEDRO FERNELY UCH PUC