- 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 |
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 |
Xl | IX | |
Yh | IY | IY vale para direccionamiento |
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 | Modo | Registro | Inmediato | Directo | Indirecto | Indexado |
Registro | ||||||
Inmediato | No se puede tener inmediato a la izquierda | |||||
Directo | Estas combinaciones no se pueden | |||||
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