Indice
1.
Arquitectura del microprocesador
2. Programación
Básica
3. Manipulación de
cadenas (Strings)
4. Programación de
E/S
5. Macros
6. Programación
modular
7. Programación
híbrida
8.
Conclusión
9.
Bibliografía
1. Arquitectura del
microprocesador
Introducción
Con la aparición de las computadoras
personales (PC) y la reducción en el costo de las
mismas, el microprocesador
se convirtió en uno de los dispositivos
electrónicos más importantes en la historia de la electrónica.
Básicamente, un microprocesador
es un circuito electrónico de muy alta escala de
integración, capaz de realizar una
infinidad de tareas de forma repetitiva a velocidades muy altas.
Esto se logra por medio de la lógica
dictada por un conjunto de instrucciones que el microprocesador
interpreta y ejecuta y que recibe el nombre de programa.
Desde su aparición en 1971 el microprocesador ha sufrido
una gran cantidad de cambios, todos ellos hacia el lado de
aumentar su capacidad y velocidad de
procesamiento.
Para poder utilizar
todo el potencial que encierra un microprocesador, es necesario
conocer y comprender su lenguaje
natural, esto es: el lenguaje
ensamblador.
Importancia del lenguaje ensamblador
El lenguaje
ensamblador es
la forma más básica de programar un microprocesador
para que éste sea capaz de realizar las tareas o los
cálculos que se le requieran.
El lenguaje
ensamblador es conocido como un lenguaje de bajo nivel, esto
significa que nos permite controlar el 100 % de las funciones de un
microprocesador, así como los periféricos asociados a éste.
A diferencia de los lenguajes de alto nivel, por ejemplo
"Pascal",
el lenguaje
ensamblador no
requiere de un compilador, esto es debido a que las instrucciones
en lenguaje ensamblador son traducidas directamente a código
binario y después son colocadas en memoria para que
el microprocesador las tome directamente.
Aprender a programar en lenguaje ensamblador no es fácil,
se requiere un cierto nivel de conocimiento
de la arquitectura y
organización de las computadoras,
además del conocimiento
de programación en algún otro
lenguaje
Ventajas del lenguaje ensamblador:
Desventajas del lenguaje ensamblador:
- Repetición constante de grupos de
instrucciones - No existe una sintaxis estandarizada
- Dificultad para encontrar errores en los programas
(bugs)
Historia de los
procesadores
Con la aparición de los circuitos
integrados, la posibilidad de reducir el tamaño de
algunos dispositivos electrónicos se vio enormemente
favorecida. Los fabricantes de controladores integrados,
calculadoras y algunos otros dispositivos comenzaron a solicitar
sistemas
integrados en una sola pastilla, esto dio origen a la
aparición de los microprocesadores.
Microprocesadores de 4 bits
En 1971, una compañía que se dedicaba a la
fabricación de memorias
electrónicas lanzó al mercado el primer
microprocesador del mundo. Este microprocesador fue el resultado
de un trabajo encargado por una empresa que
se dedicaba a la fabricación de calculadoras
electrónicas. El 4004 era un microprocesador de 4 bits
capaz de direccionar 4096 localidades de memoria de 4 bits
de ancho. Este microprocesador contaba con un conjunto de 45
instrucciones y fue ampliamente utilizado en los primeros
videojuegos y sistemas de
control.
Microprocesadores de 8 bits
Con la aparición de aplicaciones más complejas para
el microprocesador y el gran éxito
comercial del 4004, Intel decidió lanzar al mercado un nuevo
microprocesador, el 8008, éste fue el primer
microprocesador de 8 bits. Las características de este microprocesador
fueron:
- Capacidad de direccionamiento de 16 Kb
- Memoria de 8 bits
- Conjunto de 48 instrucciones
Este microprocesador tuvo tanto éxito,
que en cosa de dos años su capacidad de proceso fue
insuficiente para los ingenieros y desarrolladores, por lo cual
en 1973 se liberó el 8080. Este microprocesador fue una
versión mejorada de su predecesor y las mejoras
consistieron en un conjunto más grande de instrucciones,
mayor capacidad de direccionamiento y una mayor velocidad de
procesamiento.
Finalmente, en 1977, Intel anunció la aparición del
8085. Este era el último microprocesador de 8 bits y
básicamente idéntico al 8080. Su principal mejora
fue la incorporación del reloj temporizador dentro de la
misma pastilla.
Microprocesadores de 16 bits
En 1978, Intel lanzó al mercado el 8086 y un poco
más tarde el 8088. Estos dos microprocesadores
contaban con registros
internos de 16 bits, tenían un bus de datos externo de
16 y 8 bits respectivamente y ambos eran capaces de direccionar
1Mb de memoria por medio de un bus de direcciones de 20
líneas.
Otra característica importante fue que estos dos
microprocesadores eran capaces de realizar la
multiplicación y la división por hardware, cosa que los
anteriores no podían.
Finalmente apareció el 80286. Este era el último
microprocesador de 16 bits, el cual era una versión
mejorada del 8086. El 286 incorporaba una unidad adicional para
el manejo de memoria y era capaz de direccionar 16Mb en lugar de
1Mb del 8086.
Microprocesadores de 32 bits
El 80386 marco el inicio de la aparición de los
microprocesadores de 32 bits. Estos microprocesadores
tenían grandes ventajas sobre sus predecesores, entre las
cuales se pueden destacar: direccionamiento de hasta 4Gb de
memoria, velocidades de operación más altas,
conjuntos de
instrucciones más grandes y además contaban con
memoria interna (caché) de 8Kb en las versiones más
básicas.
Del 386 surgieron diferentes versiones, las cuales se listan a
continuación.
Modelo | Bus de Datos | Coprocesador matemático |
80386DX | 32 | Si |
80386SL | 16 | No |
80386SX | 16 | No |
80486SX | 32 | No |
80486DX | 32 | Si |
Terminales del
microprocesador
En esta sección se realizará una breve descripción del conjunto de terminales del
microprocesador más representativo de la familia
80×86.
El microprocesador 8086 puede trabajar en dos modos diferentes:
el modo mínimo y el modo máximo. En el modo
máximo el microprocesador puede trabajar en forma conjunta
con un microprocesador de datos
numérico 8087 y algunos otros circuitos
periféricos. En el modo mínimo el
microprocesador trabaja de forma más autónoma al no
depender de circuitos
auxiliares, pero
esto a su vez le resta flexibilidad.
En cualquiera de los dos modos, las terminales del
microprocesador se pueden agrupar de la siguiente
forma:
- Alimentación
- Reloj
- Control y estado
- Direcciones
- Datos
El 8086 cuenta con tres terminales de alimentación:
tierra (GND)
en las terminales 1 y 20 y Vcc=5V en la terminal 40.
En la terminal 19 se conecta la señal de reloj, la cual
debe provenir de un generador de reloj externo al
microprocesador.
El 8086 cuenta con 20 líneas de direcciones (al igual que
el 8088). Estas líneas son llamadas A0 a A19 y
proporcionan un rango de direccionamiento de 1MB.
Para los datos, el 8086 comparte las 16 líneas más
bajas de sus líneas de direcciones, las cuales son
llamadas AD0 a AD15. Esto se logra gracias a un canal de datos y
direcciones multiplexado.
En cuanto a las señales de control y
estado tenemos
las siguientes:
La terminal MX/MN controla el cambio de modo
del microprocesador.
Las señales S0 a S7 son señales de estado,
éstas indican diferentes situaciones acerca del estado del
microprocesador.
La señal RD en la terminal 32 indica una operación
de lectura.
En la terminal 22 se encuentra la señal READY. Esta
señal es utilizada por los diferentes dispositivos de E/S
para indicarle al microprocesador si se encuentran listos para
una transferencia.
La señal RESET en la terminal 21 es utilizada para
reinicializar el microprocesador.
La señal NMI en la terminal 17 es una señal de
interrupción no enmascarable, lo cual significa que no
puede ser manipulada por medio de software.
La señal INTR en la terminal 18 es también una
señal de interrupción, la diferencia radica en que
esta señal si puede ser controlada por software. Las interrupciones
se estudian más adelante.
La terminal TEST se utiliza
para sincronizar al 8086 con otros microprocesadores en una
configuración en paralelo.
Las terminales RQ/GT y LOCK se utilizan para controlar el trabajo en
paralelo de dos o mas microprocesadores.
La señal WR es utilizada por el microprocesador cuando
éste requiere realizar alguna operación de escritura con
la memoria o
los dispositivos de E/S.
Las señales HOLD y HLDA son utilizadas para controlar el
acceso al bus del sistema.
Diagrama de componentes
internos
Descripción de los componentes
La figura 2 muestra la
estructura
interna del microprocesador 8086 con base en su modelo de
programación. El microprocesador se divide
en dos bloques principales: la unidad de interfaz del bus y la
unidad de ejecución. Cada una de estas unidades opera de
forma asíncrona para maximizar el rendimiento general del
microprocesador.
Unidad de ejecución
Este elemento del microprocesador es el que se encarga de
ejecutar las instrucciones. La unidad de ejecución
comprende el conjunto de registros de
propósito general, el registro de
banderas y la unidad aritmético-lógica.
Unidad de interfaz de bus
Esta unidad, la cual se conoce como BIU (Bus Interface Unit),
procesa todas las operaciones de
lectura/escritura
relacionadas con la memoria o
con dispositivos de
entrada/salida, provenientes de la unidad de
ejecución. Las instrucciones del programa que se
está ejecutando son leídas por anticipado por esta
unidad y almacenadas en la cola de instrucciones, para
después ser transferidas a la unidad de
ejecución.
Unidad aritmético-lógica
Conocida también como ALU, este componente del
microprocesador es el que realmente realiza las operaciones
aritméticas (suma, resta, multiplicación y
división) y lógicas (and, or, xor, etc.) que se
obtienen como instrucciones de los programas.
Buses internos (datos y direcciones)
Los buses internos son un conjunto de líneas paralelas
(conductores) que interconectan las diferentes partes del
microprocesador.
Existen dos tipos principales: el bus de datos y el bus de
direcciones. El bus de datos es el encargado de transportar los
datos entre las distintas partes del microprocesador; por otro
lado, el bus de direcciones se encarga de transportar las
direcciones para que los datos puedan ser introducidos o
extraídos de la memoria o dispositivos de
entrada y salida.
Cola de instrucciones
La cola de instrucciones es una pila de tipo FIFO (primero en
entrar, primero en salir) donde las instrucciones son almacenadas
antes de que la unidad de ejecución las
ejecute.
Registros de propósito general
El microprocesador 8086 cuenta con cuatro registros de
propósito general, los cuales pueden ser usados libremente
por los programadores. Estos registros reciben los nombres
siguientes:
AX (Acumulador) Este registro es el
encargado de almacenar el resultado de algunas operaciones
aritméticas y lógicas.
BX (Base) Este registro es utilizado para calcular direcciones
relativas de datos en la memoria.
CX (Contador) Su función
principal es la de almacenar el número de veces que un
ciclo de instrucciones debe repetirse.
DX (Datos) Por lo general se utiliza para acceder a las variables
almacenadas en la memoria.
Registros apuntadores
El 8086 también cuenta con dos registros apuntadores SP y
BP. Estos registros reciben su nombre por que su función
principal es la de apuntar a alguna dirección de memoria especifica.
SP (Apuntador de pila) Se encarga de controlar el acceso de los
datos a la pila de los programas. Todos los programas en lenguaje
ensamblador utilizan una pila para almacenar datos en forma
temporal.
BP (Apuntador Base) Su función es la de proporcionar
direcciones para la transferencia e intercambio de
datos.
Registros índices
Existen dos registros llamados SI y DI que están
estrechamente ligados con operaciones de cadenas de datos.
SI (Índice Fuente) Proporciona la dirección inicial para que una cadena sea
manipulada.
DI (Índice Destino) Proporciona la dirección de
destino donde por lo general una cadena será almacenada
después de alguna operación de
transferencia.
Registros de segmento
El 8086 cuenta con cuatro registros especiales llamados registros
de segmento.
CS (Segmento de código)
Contiene la dirección base del lugar donde inicia el
programa almacenado en memoria.
DS (Segmento de datos) Contiene la dirección base del
lugar del área de memoria donde fueron almacenadas las
variables del
programa.
ES (Segmento extra) Este registro por lo general contiene la
misma dirección que el registro DS.
SS (Segmento de Pila) Contiene la dirección base del lugar
donde inicia el área de memoria reservada para la
pila.
Registro apuntador de instrucciones
IP (Apuntador
de instrucciones) Este registro contiene la dirección de
desplazamiento del lugar de memoria donde está la
siguiente instrucción que será ejecutada por el
microprocesador.
Registro de estado
Conocido también como registro de banderas (Flags), tiene
como función principal almacenar el estado
individual de las
diferentes condiciones que son manejadas por el microprocesador.
Estas condiciones por lo general cambian de estado después
de cualquier operación aritmética o
lógica:
CF (Acarreo) Esta bandera indica el acarreo o préstamo
después de una suma o resta.
OF (Sobreflujo) Esta bandera indica cuando el resultado de una
suma o resta de números con signo sobrepasa la capacidad
de almacenamiento de
los registros.
SF (Signo) Esta bandera indica si el resultado de una
operación es positivo o negativo. SF=0 es positivo, SF=1
es negativo.
DF (Dirección) Indica el sentido en el que los datos
serán transferidos en operaciones de manipulación
de cadenas. DF=1 es de derecha a izquierda y DF=0 es de izquierda
a derecha.
ZF (Cero) Indica si el resultado de una operación
aritmética o lógica fue cero o diferente de cero.
ZF=0 es diferente y ZF=1 es cero.
IF (interrupción) Activa y desactiva la terminal INTR del
microprocesador.
PF (paridad) Indica la paridad de un número. Si PF=0 la
paridad es impar y si PF=1 la paridad es par.
AF (Acarreo auxiliar) Indica si después de una
operación de suma o resta ha ocurrido un acarreo de los
bits 3 al 4.
TF (Trampa) Esta bandera controla la ejecución paso por
paso de un programa con fines de depuración.
Funcionamiento interno
(ejecución de un programa)
Para que un microprocesador ejecute un programa es necesario que
éste haya sido ensamblado, enlazado y cargado en
memoria.
Una vez que el programa se encuentra en la memoria, el
microprocesador ejecuta los siguientes pasos:
1.- Extrae de la memoria la instrucción que va a ejecutar
y la coloca en el registro interno de instrucciones.
2.- Cambia el registro apuntador de instrucciones (IP) de modo
que señale a la siguiente instrucción del
programa.
3.- Determina el tipo de instrucción que acaba de
extraer.
4.- Verifica si la instrucción requiere datos de la
memoria y, si es así, determina donde están
situados.
5.- Extrae los datos, si los hay, y los carga en los registros
internos del CPU.
6.- Ejecuta la instrucción.
7.- Almacena los resultados en el lugar apropiado.
8.- Regresa al paso 1 para ejecutar la instrucción
siguiente.
Este procedimiento lo
lleva a cabo el microprocesador millones
de veces por segundo.
Manejo de memoria
Segmentación
El microprocesador 8086, como ya se mencionó, cuenta
externamente con 20 líneas de direcciones, con lo cual
puede direccionar hasta 1 MB (00000h–FFFFFh) de localidades de
memoria. En los días en los que este microprocesador fue
diseñado, alcanzar 1MB de direcciones de memoria era algo
extraordinario, sólo que existía un problema:
internamente todos los registros del microprocesador tienen una
longitud de 16 bits, con lo cual sólo se pueden
direccionar 64 KB de localidades de memoria. Resulta obvio que
con este diseño
se desperdicia una gran cantidad de espacio de almacenamiento;
la solución a este problema fue la segmentación.
La segmentación consiste en dividir la memoria
de la computadora
en segmentos. Un segmento es un grupo de
localidades con una longitud mínima de 16 bytes y
máxima de 64KB.
La mayoría de los programas diseñados en lenguaje
ensamblador y en cualquier otro lenguaje definen cuatro
segmentos. El segmento de código, el segmento de datos, el
segmento extra y el segmento de pila.
A cada uno de estos segmentos se le asigna una dirección
inicial y ésta es almacenada en los registros de segmento
correspondiente, CS para el código, DS para los datos, ES
para el segmento extra y SS para la
pila.
Dirección física
Para que el microprocesador pueda acceder a cualquier localidad
de memoria dentro del rango de 1MB, debe colocar la
dirección de dicha localidad en el formato de 20 bits.
Para lograr esto, el microprocesador realiza una operación
conocida como cálculo de
dirección real o física. Esta
operación toma el contenido de dos registros de 16 bits y
obtiene una dirección de 20 bits.
La formula que utiliza el microprocesador es la siguiente:
Dir. Física =
Dir. Segmento * 10h + Dir. Desplazamiento
Por ejemplo: si el microprocesador quiere acceder a la variable X
almacenada en memoria, necesita conocer su dirección
desplazamiento. La dirección segmento para las variables
es proporcionada por el registro DS. Para este caso, supongamos
que X tiene el desplazamiento 0100h dentro del segmento de datos
y que DS tiene la dirección segmento 1000h, la
dirección física de la variable X dentro del
espacio de 1Mb será:
Dir. Física = 1000h * 10h +0100h
Dir. Física = 10000h + 0100h
Dir. Física = 10100h (dirección en formato de 20
bits).
Dirección efectiva
(desplazamiento)
La dirección efectiva (desplazamiento) se refiere a la
dirección de una localidad de memoria con respecto a la
dirección inicial de un segmento. Las direcciones
efectivas sólo pueden tomar valores entre
0000h y FFFFh, esto es porque los segmentos están
limitados a un espacio de 64 Kb de memoria.
En el ejemplo anterior, la dirección real de la variable X
fue de 10100h, y su dirección efectiva o de desplazamiento
fue de 100h con respecto al segmento de datos que comienza en la dirección
10000h.
Direccionamiento de los datos
En la mayoría de las instrucciones en lenguaje
ensamblador, se hace referencia a datos que se encuentran
almacenados en diferentes medios, por
ejemplo: registros, localidades de memoria, variables, etc.
Para que el microprocesador ejecute correctamente las
instrucciones y entregue los resultados esperados, es necesario
que se indique la fuente o el origen de los datos con los que va
a trabajar, a esto se le conoce como direccionamiento de
datos.
En los microprocesadores 80×86 existen cuatro formas de indicar
el origen de los datos y se llaman modos de direccionamiento.
Para explicar estos cuatro modos, tomaremos como ejemplo la
instrucción más utilizada en los programas en
ensamblador, la instrucción MOV.
La instrucción MOV permite transferir (copiar) información entre dos operandos; estos
operandos pueden ser registros, variables o datos directos
colocados por el programador. El formato de la instrucción
MOV es el siguiente:
Mov Oper1,Oper2
Esta instrucción copia el contenido de Oper2 en Oper1.
Direccionamiento directo
Este modo se conoce como directo, debido a que en el segundo
operando se indica la dirección de desplazamiento donde se
encuentran los datos de origen.
Ejemplo:
Mov AX,[1000h] ;Copia en AX lo que se encuentre almacenado en
; DS:1000h
Direccionamiento inmediato
En este modo, los datos son proporcionados directamente como
parte de la instrucción.
Ejemplo:
Mov AX,34h ;Copia en AX el número 34h hexadecimal
Mov CX,10 ;Copia en CX el número 10 en decimal
Direccionamiento por registro
En este modo de direccionamiento, el segundo operando es un
registro, el cual contiene los datos con los que el
microprocesador ejecutará la instrucción.
Ejemplo:
Mov AX,BX ;Copia en AX el contenido del registro BX
Direccionamiento indirecto por registro
Finalmente, en el modo indirecto por registro, el segundo
operando es un registro, el cual contiene la dirección
desplazamiento correspondiente a los datos para la
instrucción.
Ejemplo:
Mov AX,[BX] ; Copia en AX el dato que se encuentre en la
localidad de
;memoria DS:[BX]
Los paréntesis cuadrados sirven para indicar al
ensamblador que el número no se refiere a un dato, si no
que se refiere a la localidad de memoria.
En los siguientes capítulos se muestran varios programas,
en los cuales podrá identificar los diferentes
modos de
direccionamiento de datos.
2. Programación Básica
Para comenzar con la programación en lenguaje
ensamblador, es necesario contar con un conjunto de herramientas
de programación. Este conjunto de herramientas
consta de un editor de texto capaz de
producir archivos en
código
ASCII, un ensamblador y un enlazador.
Para propósitos de este trabajo, se utilizaran los
siguientes programas:
El ensamblador PASS32
El editor de texto EDIT
proporcionado con todas las versiones de MS-DOS y
Windows.
PASS32 es un ensamblador y enlazador capaz de producir
código ejecutable de 16 y 32 bits.
Ambos programas se encuentran en el CD-ROM que se
incluye como parte de este documento.
La razón por la cual se seleccionaron estos programas, es
que pertenecen al software bajo licencia GNU, lo cual permite que
sean utilizados por instituciones
educativas sin fines de lucro. Esta característica permite
que dichos programas sean utilizados sin caer en la
práctica de la piratería informática por no comprar
licencias.
Formatos de
instrucciones
En el lenguaje ensamblador existen tres tipos de instrucciones:
instrucciones con dos operandos, instrucciones con un operando e
instrucciones con operandos implícitos.
El campo nemónico es ocupado por cualquiera de las
instrucciones que forman parte del conjunto de la familia
x86.
Ejemplo: Mov (Transferir)
En los dos campos siguientes Reg significa que el operando puede
ser un registro, Mem indica que puede ser una dirección de
memoria y dato indica que el operando puede ser un dato colocado
directamente por el programador. Los campos dos y tres se
encuentran entre paréntesis cuadrados para indicar que son
opcionales en algunas instrucciones.
Los siguientes son algunos ejemplos de instrucciones de las tres
formas:
Instrucción con dos operandos:
Mov AX,BX
En este caso Mov es el nemónico, AX es el operando 1 y BX
es el operando 2.
Instrucción con un operando:
INC BX
En este caso INC es el nemónico y BX es el único
operando.
Finalmente las instrucciones con operandos implícitos o
sin operandos:
PUSHF
Donde PUSHF es el nemónico y único elemento de la
instrucción.
Formato de un programa
En esta sección aprenderemos como se constituye el
código fuente de un programa en lenguaje ensamblador.
El siguiente listado se utilizará para mostrar las
diferentes partes.
.COMMENT
*************************************************************************
PRIMERO.ASM Ejemplo de un programa en lenguaje ensamblador.
Juan Carlos Guzmán C. Ensamblado con Pass32 Versión
2.5.
Abril, 2000.
=========================================================================
*************************************************************************
.MODEL TINY; Modelo de
memoria para el programa
.DATA; Declaración de variables
Mensaje db 'Mi primer programa',10,13,'$'
.CODE; Cuerpo del programa
INICIO:; Punto de entrada al programa
mov dx,OFFSET Mensaje ; Dirección de la cadena de
texto
mov ah,9 ; Función para imprimir cadenas
int 21h ; Llamada al sistema
operativo
mov ah,4ch ; Función para terminar un programa
int 21h ; Llamada al sistema operativo
END INICIO ; Fin del bloque principal del programa
END
Un programa en lenguaje ensamblador se compone de las
siguientes partes:
- Área de comentarios
- Definición del modelo de memoria
- Área de datos
- Cuerpo del programa
El área de comentarios sirve para incluir
comentarios acerca del programa que se está elaborando,
comienza con la directiva .COMMENT y el comentario es colocado
entre dos caracteres ‘*’.
La definición del modelo de memoria es la parte donde se
indica que tipo de código se va generar (16 o 32 bits). En
este trabajo sólo se escribirán programas
ejecutables .COM, por lo que siempre se usa la directiva .MODEL
TINY.
El área de datos es el lugar donde deben ser declaradas
las constantes y variables del programa. Las variables son
declaradas después de la directiva .DATA y las constantes
después de .CONST.
En el cuerpo del programa es donde se colocan las instrucciones
en lenguaje ensamblador que se encargarán de realizar las
tareas deseadas. El cuerpo del programa comienza con la directiva
.CODE y termina con la directiva END. Esta parte corresponde al
Begin y End de un programa en lenguaje Pascal.
Adicionalmente se debe indicar un punto de entrada al programa.
El punto de entrada se indica por medio de una etiqueta antes de
la primer instrucción real del programa. En el ejemplo
anterior el punto de entrada es INICIO: y el punto final de las
instrucciones se indica por medio de la instrucción END
INICIO.
Cuando se requiere comentar las instrucciones de un programa, se
debe colocar un punto y coma (;) y así el ensamblador
interpreta todo lo que sigue como un comentario de una sola
línea. Si requiere comentarios de más de una
línea puede usar la directiva .COMMENT.
Proceso de ensamble y ligado de
un programa
Este proceso es muy
sencillo y se describe a continuación:
Si está trabajando en MS-DOS siga
estos pasos:
1.- Escriba el programa, tal y como aparece en el listado
anterior, usando su editor de texto preferido.
2.- Guárdelo con algún nombre y la extensión
.ASM.
3.- En el símbolo del MS-DOS escriba lo siguiente
C:PASS32BIN>PASS32 Nombre.ASM –t <Enter>
4.- Ejecute el programa .COM que se genera.
Para probar el programa abra una ventana de MS-DOS y seleccione
el programa haciendo doble clic sobre el icono.
Directivas de ensamble (Seudo
instrucciones)
Pass32 cuenta con algunas palabras reservadas que cumplen tareas
especiales para facilitar la programación en ensamblador,
estas palabras son llamadas seudo instrucciones o directivas de
ensamble.
La siguiente es una lista de las directivas de ensamble
más utilizadas en Pass32:
DB Reserva un byte en memoria
DW Reserva una palabra (Word) en
memoria o 2 bytes
DD Reserva una palabra doble (Double Word)
.EQU Se utiliza para reemplazar símbolos por valores
PROC-ENDP Se utilizan para declarar procedimientos en
los programas
.MACRO-ENDM Se utilizan para declarar macros
DUP Sirve para inicializar cadenas de caracteres o arreglos
numéricos
.INCLUDE Se utiliza para obtener datos o subrutinas de otros
programas
.EXTERN Declara un símbolo como externo, trabaja en
conjunto con .INCLUDE .PUBLIC Declara un símbolo como
público
Los programas incluidos como ejemplos muestran la forma de
utilizar estas directivas.
Instrucciones de transferencia de datos
Los microprocesadores 80×86 cuentan con algunas instrucciones
básicas de transferencia de información de acuerdo con los modos de
direccionamiento explicados en el capítulo anterior. Las
instrucciones más representativas del grupo de
transferencia son:
MOV.- Transfiere (copia) contenidos. Su formato es MOV OP1,OP2.
Esta instrucción copia el contenido de OP2 en OP1.
Ejemplo:
Mov AX,0 ; AX=0
LEA.- Carga un registro con la dirección de desplazamiento
de alguna variable en memoria. Su formato es LEA REG,Variable.
Ejemplo:
.Data
Mensaje db ‘Hola’,’$’
.Code
——
——
Lea DX,Mensaje ;DS:DX->Mensaje
LDS.- Inicializa el registro DS
LES.- Inicializa el registro ES
Nota:
Las instrucciones LDS y LES modifican directamente el contenido
de los registros de segmento DS y ES, por lo cual se recomienda
que sólo sean utilizadas por programadores avanzados.
XCHG.- Intercambia contenidos. Su formato es XCHG OP1,OP2. El
resultado es que el contenido de OP2 se pasa a OP1 y el de OP1 se
pasa a OP2.
Ejemplo:
XCHG AX,BX ; AX->BX, BX->AX
El siguiente programa muestra la forma
de usar las instrucciones de transferencia, además de
algunas directivas de ensamble.
Inicialmente, el programa define un arreglo de 10 elementos
llamado Array1, y lo inicializa con ceros. Después,
utilizando la instrucción Mov, copia el número 10
en el registro AX y el 5 en el registro BX. Por medio de la
instrucción Lea, el registro DX es cargado con la
dirección de memoria donde comienza Array1 y finalmente
intercambia el contenido de los registros AX y BX por medio de la
instrucción XCHG.
Debido a que el ensamblador es un lenguaje de bajo nivel, es
decir que el programador se encuentra en contacto directo con los
componentes de la computadora,
no existen instrucciones que nos permitan ver el contenido de los
registros o los resultados de las operaciones en pantalla, es por
esto que la mayoría de los programas no muestran datos en
pantalla.
.COMMENT
*
Programa: Trans1.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra es uso de las
operaciones para transferencia de datos.
El programa realmente no hace nada que sea visible al usuario, es
solo con fines ilustrativos.
*
.MODEL tiny
.DATA
Array1 db 10 dup (0) ;Arreglo de 10 elementos iniciali-
;zados en cero.
.CODE
inicio: ;Punto de entrada al programa
mov AX,10 ;Copiar el número 10 dentro de AX
mov BX,5 ;Copiar le número 5 dentro de BX
lea DX,Array1 ;DX contiene la dirección efectiva de
Array1[0]
xchg AX,BX ;Intercambiar los valores
contenidos en AX y BX
mov ax,4C00h ;Terminar programa y salir al DOS
int 21h
END inicio
END
Instrucciones
aritméticas
Existen 8 instrucciones aritméticas básicas: ADD
(Suma), SUB (Resta), MUL (Multiplicación sin signo), DIV
(División sin signo), IMUL (Multiplicación con
signo), IDIV (División con signo), INC (Incremento
unitario) y DEC (Decremento unitario).
Las instrucciones ADD y SUB permiten realizar sumas y restas
sencillas y tienen el siguiente formato:
ADD Destino, Fuente
SUB Destino, Fuente
Ejemplos:
ADD AX,BX ;AX=AX+BX
ADD AX,10 ;AX=AX+10
SUB AX,BX ;AX=AX-BX
SUB AX,10 ;AX=AX-10
En las operaciones de suma y resta el resultado siempre
es almacenado en el operando de destino, el cual puede ser un
registro o una variable.
Las instrucciones INC y DEC permiten incrementar los contenidos
de los registros y de las variables almacenadas en memoria.
Ejemplos:
INC AX ;AX=AX+1
INC VAR1 ;VAR1=VAR1+1
DEC AX ;AX=AX-1
DEC VAR1 ;VAR1=VAR1-1
El siguiente programa muestra la forma de utilizar estas
instrucciones básicas:
.COMMENT
*
Programa: Addsub.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra el uso de las
instrucciones ADD, SUB, INC y DEC.
*
.MODEL TINY
.DATA
Var1 DW 10 ;Declaración de una variable de tipo entero
;inicializada con 10.
.CODE
Inicio: ;Punto de entrada al programa
Mov AX,5 ;AX=5
Mov BX,10 ;BX=10
Add AX,BX ;AX=AX+BX
Mov CX,8 ;CX=8
Add CX,Var1 ;CX=CX+Var1
Inc AX ;AX=AX+1
Dec BX ;BX=BX-1
Inc Var1 ;Var1=Var1+1
Dec Var1 ;Var1=Var1-1
Mov AX,4C00h ;Terminar programa y salir al DOS
Int 21h ;
END Inicio
END
Multiplicación
Por otro lado, las operaciones de multiplicación y
división son un poco más complejas de utilizar,
esto se debe a que debemos tomar en cuenta el tamaño de
los operandos para no sobrepasar la capacidad de almacenamiento
de los registros del microprocesador.
Existen dos instrucciones para la multiplicación, estas
son: MUL e IMUL. MUL permite realizar operaciones de
multiplicación entre operandos sin signo e IMUL permite
realizar operaciones entre operandos con signo.
La multiplicación se puede efectuar entre bytes (8 bits),
palabras (16 bits) o dobles palabras (32 bits). Solamente los
microprocesadores 386 y posteriores pueden realizar
multiplicaciones entre operandos de 32 bits.
El producto de
una multiplicación siempre tiene el doble de ancho. Si se
multiplican dos números de 8 bits, el resultado
será de 16 bits; si se multiplican dos números de
16 bits, el producto
será de 32 bits y, finalmente, si se multiplican
cantidades de 32 bits, el resultado será un número
de 64 bits.
En la multiplicación de 8 bits, con o sin signo, el
multiplicando está siempre en el registro AL. El
multiplicador puede ser cualquier registro de 8 bits o cualquier
variable. El resultado de la multiplicación se almacena en
el registro AX, que es de doble ancho que los operandos
involucrados.
Ejemplos válidos de operaciones de multiplicación
son los siguientes:
MOV BL,5 ;Cargar datos
MOV AL,10 ;
MUL BL ; AX=AL*BL
MOV AL,10
MUL número1 ; AX=AL*número1
; donde número1 es una variable de tipo byte.
En la multiplicación de 16 bits, el multiplicando
debe ser colocado en el registro AX y el resultado siempre
aparece en el par de registros DX:AX. El registro DX contiene los
16 bits más significativos de producto, mientras que el
registro AX contiene los 16 bits menos significativos del
resultado.
Ejemplos:
MOV AX,400 ;Cargar datos
MOV CX,100 ;
MUL CX ; DX:AX=AX*CX
MOV AX,400 ;
MUL numero2 ; DX:AX=AX*numero2
El siguiente programa muestra la forma de utilizar algunas de
estas operaciones de multiplicación en sus diferentes
formatos. Debido a que el ensamblador no cuenta con funciones para
imprimir información numérica en la pantalla, no es
posible mostrar los resultados; considere este ejemplo
únicamente con fines ilustrativos.
.COMMENT
*
Programa: Mul.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra el uso de las
instrucciones MUL e IMUL.
*
.MODEL TINY
.DATA
NUM1 dw 3
NUM2 db -5
.CODE
INICIO:
;MULTIPLICACIÓN DE 8 BITS CON REGISTROS
MOV BH,4 ;BH=4
MUL BH ;AX=AL*BH
;MULTIPLICACIÓN DE 16 BITS
MOV AX,-3 ;AX=-3
MUL NUM1 ;DX:AX=AX*NUM2
;MULTIPLICACIÓN DE 8 BITS CON VARIABLES
MOV AL,3 ;AL=3
IMUL NUM2 ;AX=AL*NUM2
MOV AX,4c00h
INT 21h
END INICIO
END
División
Las instrucciones para división permiten realizar
divisiones de 8, 16 o 32 bits (esta última sólo
está disponible en los microprocesadores 386 y
posteriores). Los operandos pueden ser números con signo
(IDIV) o números sin signo (DIV). El dividendo siempre
tiene el doble de ancho que el operando divisor. Esto significa
que en una división de 8 bits se divide un número
de 16 bits entre uno de 8; en una de 16 bits se divide un
número de 32 bits entre uno de 16, etc.
En la división de 8 bits, el dividendo es almacenado en el
registro AX y el divisor puede ser cualquier registro de 8 bits o
cualquier variable declarada de tipo byte. Después de la
división, el cociente es cargado en el registro AL y el
residuo en el registro AH.
Ejemplo de división sin signo:
MOV AX,10
MOV BL,5
DIV BL
Ejemplo de división con signo:
MOV AL,-10
MOV BL,2
CBW
IDIV BL
En este último ejemplo, el dividendo es cargado
en el registro AL, pero debido a las reglas del microprocesador
el dividendo debe ser de 16 bits; para lograr esto, se utiliza
una instrucción especial. La instrucción CBW
(convertir byte a palabra) permite convertir un número de
8 bits con signo en AL en un número de 16 bits con signo
en AX.
En la división de 16 bits se siguen las mismas reglas que
en la división de 8 bits, sólo que en ésta,
el dividendo se encuentra en los registro DX:AX. Después
de la división el cociente es almacenado en el registro AX
y el residuo en el registro DX. En el caso de la división
con signo, existe una instrucción que permite convertir un
número con signo de 16 bits en AX en un número con
signo de 32 bits en DX:AX.
El siguiente programa muestra la forma de utilizar algunas de
estas operaciones de división en sus diferentes formatos.
Debido a que el ensamblador no cuenta con funciones para imprimir
información numérica en la pantalla, no es posible
mostrar los resultados; considere este ejemplo únicamente
con fines ilustrativos.
.COMMENT
*
Programa: Div.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra el uso de las
instrucciones DIV e IDIV.
*
.MODEL TINY
.DATA
NUM1 db 3
NUM2 db -5
.CODE
INICIO: ;INICIO DEL PROGRAMA
MOV AX,100 ;AX=100
MOV BH,10 ;BH=10
DIV BH ;DIVISION DE 8 BITS SIN SIGNO
MOV AX,100 ;AX=100
DIV NUM1 ;DIVISION DE 8 BITS SIN SIGNO CON VARIABLES
MOV AL,-10 ;AX=-10
CBW ;EXTENSIÓN DE SIGNO A 16 BITS
IDIV num2 ;DIVISION DE 8 BITS CON SIGNO
MOV AX,4c00h ;FIN DEL PROGRAMA
INT 21h ;
END INICIO
END
Instrucciones para la
manipulación de banderas
El registro de banderas tiene diferentes funciones en cada uno de
sus bits, algunos de estos bits (banderas) pueden ser controlados
por instrucciones directas de bajo nivel; sin embargo, se debe
tener en cuenta que estas banderas están
íntimamente ligadas con funciones internas del
microprocesador, por ejemplo la línea INTR
(interrupción por hardware), acarreos, etc., y que al
manipularlas incorrectamente podemos llegar al extremo de
bloquear la
computadora. Es por esto que se recomienda que sólo
programadores experimentados modifiquen dichas banderas.
En esta sección se explicarán algunas de las
instrucciones más comunes y sus aplicaciones, pero no se
desarrollarán programas por razones de seguridad.
Control de interrupción
La terminal INTR del microprocesador puede ser activada o
desactivada directamente por los programas por medio de las
instrucciones STI y CLI. STI carga un 1 en IF, con lo cual INTR
queda habilitada; por otro lado, CLI carga un cero en IF, con lo
cual las interrupciones externas o por hardware quedan
deshabilitadas.
Control de la bandera de acarreo
La bandera de acarreo, CF, es la encargada de indicar cuando ha
ocurrido un acarreo o préstamo en operaciones de suma o
resta, también indica errores en la ejecución de
procedimientos. Existen tres instrucciones
básicas para su manipulación: STC (activar
acarreo), CLC (desactivar acarreo) y CMC (Complementar
acarreo).
Control de la bandera de dirección
La bandera de dirección, DF, es utilizada para establecer
el sentido en el que las cadenas de datos serán procesadas
por los programas. Un cero en DF indica procesamiento de
izquierda a derecha, mientras que un uno indica procesamiento de
derecha a izquierda.
Para controlar esta bandera, existen dos instrucciones, CLD
(limpiar bandera) y STD (establecer bandera). STD coloca un uno y
CLD coloca un cero.
Estas instrucciones serán aplicadas más adelante en
el capítulo 3, en el cual se desarrollan varios programas para mostrar su uso.
Instrucciones de comparación y prueba
Existen dos instrucciones especiales en el microprocesador 8086:
CMP y TEST. CMP
(Comparar) compara si dos valores son
iguales o diferentes. Su funcionamiento es similar al de la
instrucción SUB (restar), sólo que no modifica el
operando de destino, solamente modifica las banderas de signo
(SF), de cero (ZF) y de acarreo (CF).
Por ejemplo:
CMP AX,1235
Esta instrucción compara si el valor
almacenado en el registro AX es igual que el valor 1235 en
decimal.
Por otro lado, la instrucción TEST realiza la
operación AND de los operandos especificados sin que el
resultado se almacene en algún registro, modificando
únicamente ciertas banderas. Su aplicación
más común es la de probar si algún bit es
cero.
Ejemplo:
Test AL,1
Esta instrucción prueba si el bit menos significativo de
AL es 1 y
Test AL,128 prueba si el bit más significativo de AL es
1.
Por lo general estas instrucciones van seguidas de alguna de las
instrucciones de salto, las cuales se estudian en otra
sección.
Instrucciones de salto
En los lenguajes de alto nivel como Pascal y C, los programadores
pueden controlar el flujo de los programas por medio de
instrucciones condicionales compuestas; por ejemplo, en Pascal el
siguiente conjunto de instrucciones permite tomar una
decisión sobre el flujo del programa:
IF A=5 then
write("Error…");
else
A:=A+1;
En contraste, el lenguaje ensamblador no proporciona
tales mecanismos. Este tipo de decisiones se realizan por medio
de una serie de instrucciones que van teniendo un significado
consecutivo; es decir, el efecto de la instrucción
siguiente depende del resultado anterior.
El lenguaje ensamblador proporciona un conjunto de instrucciones
conocidas como instrucciones de salto. Estas instrucciones son
utilizadas en conjunto con instrucciones de comparación y
prueba para determinar el flujo del programa.
Existen dos tipos de instrucciones de salto: las instrucciones de
salto condicional y las de salto incondicional.
Las instrucciones de salto condicional, revisan si ha ocurrido
alguna situación para poder
transferir el control del programa a otra sección, por
ejemplo:
CMP AX,0
JE otro
………..
……….
otro:
……….
……….
End
En este ejemplo, la instrucción JE (Salta si es
igual) revisa si la prueba implícita en la
instrucción anterior resultó positiva, es decir, si
la comparación de AX con 0 fue cierta. En caso de que AX
sea igual a 0, JE transfiere el control del programa a las
instrucciones que se encuentran después de la etiqueta
"otro". En caso contrario ejecuta las instrucciones siguientes a
JE.
Por otro lado, las instrucciones de salto incondicional
(sólo existe una) permiten cambiar el flujo del programa
sin verificar si se cumplió alguna condición.
Ejemplo:
Mov AX,10
Jmp otro
……..
……..
otro:
……..
……..
En este ejemplo, inmediatamente después de cargar
el registro AX con el valor de 10, se transfiere el control del
programa a la instrucción que sigue después de la
etiqueta "otro".
La siguiente es una lista de las instrucciones de salto
condicional y su descripción:
JA o JNBE: Salta si está arriba o salta si no está
por debajo o si no es igual (jump if above or jump if not below
or equal). El salto se efectúa si la bandera de CF=0 o si
la bandera ZF=0.
JAE o JNB: Salta si está arriba o es igual o salta si no
está por debajo (jump if above or equal or jump if not
below). El salto se efectúa si CF=0.
JB o JNAE: Salta si está por debajo o salta si no
está por arriba o es igual (jump if below or jump if not
above or equal). El salto se efectúa si CF=1.
JBE o JNA: Salta si está por debajo o es igual o salta si
no está por arriba (jump if below or equal or jump if not
above). El salto se efectúa si CF=1 o ZF=1.
JE o JZ: Salta si es igual o salta si es cero (jump if equal or
jump if zero). El salto se efectúa si ZF=1.
JNE o JNZ: Salta si no es igual o salta si no es cero (jump if
not equal or jump if not zero). El salto se efectúa si
ZF=0.
JG o JNLE: Salta si es mayor o salta si no es menor o igual (jump
if greater or jump if not less or equal). El salto se
efectúa si ZF=0 u OF=SF.
JGE o JNL: Salta si es mayor o igual o salta si no es menor (jump
if greater or equal or jump if not less). El salto se
efectúa si SF=OF.
JL o JNGE: Salta si es menor o salta si no es mayor o igual (jump
if less or jump if not greater or equal). El salto se
efectúa si SF<>OF
JLE o JNG: Salta si es menor o igual o salta si no es mayor (jump
if less or equal or jump if not greater). El salto se
efectúa si ZF=1 o SF<>OF.
JC: Salta si hay acarreo (jump if carry). El salto se
efectúa si CF=1.
JNC: Salta si no hay acarreo (jump if no carry). El salto se
efectúa si CF=0.
JNO: Salta si no hay desbordamiento (jump if no overflow). El
salto se efectúa si OF=0.
JNP o JPO : Salta si no hay paridad o salta si la paridad es non
(Jump if no parity or jump if parity odd). El salto se
efectúa si PF=0.
JNS: Salta si no hay signo (jump if not sign). El salto se
efectúa si SF=0.
JO: Salta si hay sobreflujo (jump if overflow). El salto se
efectúa si OF=1.
JP o JPE: Salta si hay paridad o salta si la paridad es par (jump
if parity or jump if parity even). El salto se efectúa si
PF=1.
JS: Salta si hay signo (jump if sign). El salto se efectúa
si SF=1.
El siguiente programa muestra la forma de utilizar instrucciones
de saltos condicionales:
.COMMENT
*
Programa: Jumps1.Asm
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra el uso de las
instrucciones de salto condicional e incondicional
*
.MODEL TINY
.DATA
cad1 db 'Las cantidades son iguales…',13,10,'$'
cad2 db 'Las cantidades no son iguales…',13,10,'$'
.CODE
INICIO: ;Punto de entrada al programa
Mov ax,10 ;AX=10
Mov bx,10 ;BX=10
Cmp ax,bx ;Es AX=BX?
Je igual ;S¡, entonces saltar a la etiqueta igual
Lea dx,cad2 ;No, entonces imprimir Cad2
Mov ah,09h ;
Int 21h ;
Jmp salir ;saltar a la etiqueta salir
igual:
Lea dx,cad1 ;imprimir el mensaje en cad1
Mov ah,09h ;
Int 21h ;
salir:
Mov ax,4c00h ;Salir
Int 21h ;
END INICIO
END
Este programa ilustra de forma básica la
utilización de las instrucciones de salto, tanto
condicionales como incondicionales.
Primeramente, el programa inicializa los registros AX y BX con el
valor 10 en decimal; después utiliza la instrucción
CMP para comparar el contenido de ambos registros; la
instrucción JE (Salta si es igual) verifica la bandera de
cero ZF, si ZF=1 significa que los contenidos son iguales y por
lo tanto efectúa el salto hacia la etiqueta "Igual", en
caso de que ZF=0 el programa continúa su flujo normal
hasta encontrar la instrucción JMP; en este caso la
instrucción JMP se utiliza para evitar llegar a la
etiqueta "Igual" en el caso de que los datos sean diferentes.
El formato para utilizar las instrucciones de salto es
idéntico al mostrado en este programa, solamente hay que
identificar cual es la condición que queremos probar, para
de esta forma seleccionar adecuadamente la instrucción de
salto.
Instrucciones para
ciclos
El lenguaje ensamblador cuenta con una instrucción muy
poderosa que permite la programación de ciclos finitos, la
instrucción LOOP.
Esta instrucción trabaja en forma conjunta con el registro
contador CX. El formato general de esta instrucción
es:
Mov CX,No_Veces
Etiqueta:
——-
Loop Etiqueta
La instrucción LOOP ejecuta las instrucciones que se
encuentran entre la Etiqueta: y Loop Etiqueta el numero de veces
que indique el campo No_Veces.
Por ejemplo, el siguiente grupo de instrucciones incrementa en 1
el registro AX, esto lo repite 10 veces.
Mov CX,10 ;10 veces
Otro:
Inc AX ; AX=AX+1
Loop Otro
La instrucción Loop decrementa el registro CX en cada
iteración y se detiene cuando CX es igual a cero.
El siguiente programa da un ejemplo más ilustrativo:
.COMMENT
*
Programa: Loop.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa calcula la sucesión de
Fibonacci para los 10 primeros términos de la serie,
utilizando para ello un
ciclo controlado por la instrucción Loop.
La sucesión está formada por números, de
modo tal que cada número es la suma de los dos
anteriores-
Ejemplo:
1,1,2,3,5,8,13,21,34,55….
*
.MODEL tiny
.CODE
Inicio: ;Punto de entrada al programa
Mov AX,0 ;AX=0
Mov BX,1 ;BX=1 Estos son los dos primeros elementos 0+1=1
Mov CX,10 ;Repetir 10 veces
Repite:
Mov DX,AX ;DX=AX
Add DX,BX ;DX=AX+BX
Mov AX,BX ;Avanzar AX
Mov BX,DX ;Avanzar BX
Loop Repite ;siguiente número
Mov AX,4C00h ;Terminar programa y salir al DOS
Int 21h ;
END Inicio
END
Instrucciones
lógicas
El microprocesador 8086 cuenta con un grupo de instrucciones
lógicas que operan a nivel de bit, estas instrucciones
son: AND, OR, XOR y NOT.
A continuación se muestran las tablas de verdad de estas
instrucciones:
Las instrucciones que se enlistan antes requieren dos
operandos, a excepción de la operación NOT que
sólo requiere uno.
En la figura se puede observar que para la operación AND,
si los dos operandos son 1, el resultado será 1, en
cualquier otra situación será 0.
La operación OR establece el resultado a 1 si cualquiera
de los dos operandos es 1, de lo contrario el resultado
será 0.
La instrucción XOR coloca en 0 el resultado si los
operandos son iguales, de lo contrario establece 1.
Finalmente, la instrucción NOT cambia de estado todos los
bits del operando, los unos por ceros y los ceros por unos.
La principal aplicación de estas instrucciones es el
enmascaramiento de información. La operación AND
nos permite poner a cero cualquier bit de un dato; la
operación OR nos permite poner a uno cualquier bit de un
dato y la operación XOR permite borrar el contenido de
algún registro o localidad de memoria, así como
para negar algún bit.
El siguiente programa muestra la forma de utilizar estas
instrucciones:
.COMMENT
*
Programa: AndOr.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra el uso de las
instrucciones
AND, OR, XOR y NOT.
*
.MODEL TINY
.DATA
Mascara1 db 11111110b
Mascara2 db 00000001b
Dato1 db 11111111b
Dato2 db 00000000b
.CADE
INICIO:
Mov cx,0000h ;CX=0;
Mov al,dato1 ;al=dato1
And al,mascara1 ;al=al and mascara1
Mov ah,dato2 ;ah=dato2
Or ah,mascara2 ;ah=ah or mascara2
Xor bx,bx ;bx=0
Not cx ;cx=not cx
Mov ax,4c00h
Int 21h
END INICIO
END
El programa del listado 8 declara cuatro variables de
tipo byte: Mascara1, Mascara2, Dato1 y Dato2; después
inicializa CX=00h, Al=FFh, Ah=00h; al aplicar una
operación and de FFh y FEh, el resultado es FEh, en otras
palabras, se apagó el bit menos significativo de al; la
siguiente operación es un OR entre 00 y 01, lo cual da
como resultado que se encienda el bit menos significativo del Ah,
el resultado es 01. La siguiente operación es XOR BX,BX,
la cual al ser aplicada sobre el mismo operando da como resultado
que dicho operando sea borrado. Por ultimo, la operación
NOT CX cambia todos los bits de 0 a 1 y viceversa, por lo cual
CX=11h.
Instrucciones de rotación
y desplazamiento
El microprocesador cuenta con un conjunto de instrucciones que
permiten la manipulación de las posiciones individuales de
los bits dentro de un registro o localidad de memoria, estas
instrucciones se encuentran divididas en dos grupos:
instrucciones de rotación e instrucciones de
desplazamiento (también conocidas como instrucciones para
corrimientos).
Las instrucciones para rotación son cuatro y nos permiten
mover de forma cíclica los bits que forman parte de un
registro o localidad de memoria, estas instrucciones son ROL,
ROR, RCL , RCR.
ROL y ROR funcionan de forma muy semejante; al ejecutar una
instrucción ROL, el bit más significativo del dato
es desplazado hacia la bandera de acarreo y también hacia
la posición del bit memos significativo, por lo cual todos
los bits restantes son rotados o movidos hacia la izquierda. La
instrucción ROR funciona igual, sólo que
ésta trabaja hacia la derecha.
Las instrucciones RCL y RCR permiten la rotación de los
bits de una localidad de memoria o registro, considerando
también el contenido de la bandera de acarreo. En el caso
de RCL, el bit más significativo pasa hacia la bandera de
acarreo, el bit que se encontraba en la bandera de acarreo pasa
al bit menos significativo y finalmente los bits restantes son
rotados hacia la izquierda. La instrucción RCR funciona
igual, pero aplica su rotación hacia la derecha.
Para ilustrar el uso de estas instrucciones, tomaremos como
ejemplo la instrucción ROL (Rotación a la
izquierda).
Las instrucciones de rotación y desplazamiento tienen
diferentes formas de utilizarse dependiendo del modelo del
microprocesador, los siguientes ejemplos muestran estas
formas:
En el microprocesador 8086 existen dos formas, con contador
implícito y con contador explícito.
La forma con contador implícito se utiliza para realizar
una sola rotación a la vez y tiene el siguiente
formato:
ROL AX,1 ;Rotar AX un bit
La forma con contador explícito se utiliza para realizar
rotaciones n veces sobre un registro o localidad de memoria:
MOV CL,3 ;Número de rotaciones
ROL AX,CL ; Rotar AX 3 veces
En el microprocesador 80386 y superiores existe una variante de
contador implícito, la cual nos permite establecer el
contador directamente como un operando, su forma es la
siguiente:
ROL AX,3 ; Rotar AX 3 veces, sólo en 80386 y
posteriores
En el caso de las instrucciones de desplazamiento, también
existen cuatro: SHL, SHR, SAL, SAR.
SHL y SHR se utilizan para desplazar los bits de un registro o
localidad de memoria, sin considerar el signo de su
contenido.
SAL y SAR se utilizan para desplazar los bits de un registro o
localidad de memoria, considerando su contenido como una cantidad
con signo.
Las instrucciones SHL y SHR funcionan de forma idéntica,
sólo que en sentidos opuestos. La instrucción SHL
inserta un 0 en la posición del bit menos significativo y
desplaza todos los demás bits una posición hacia la
izquierda, colocando el bit más significativo en la
bandera de acarreo. La instrucción SHR inserta un 0 en la
posición más significativa, desplaza todos los bit
una posición hacia la derecha y finalmente coloca el bit
menos significativo en la bandera de acarreo.
Algunos ejemplos de su uso son los siguientes:
SHL AX,1 ; Desplaza el contenido de AX una posición a la
izquierda
MOV CX,3 ; Número de veces
SHR AX,CL ; Desplaza AX 3 veces hacia la derecha
SHL BX,4 ; Desplaza BX 4 veces hacia la izquierda, sólo en
386 y posteriores
Las dos instrucciones restantes SAL y SAR son muy parecidas a las
instrucciones SHL y SHR, sólo que estas dos instrucciones
consideran el contenido de los registros como cantidades con
signo, por lo cual el bit en la posición más
significativa del dato (bit de signo) se conserva sin cambio.
El siguiente ejemplo muestra el uso de las instrucciones de
rotación y desplazamiento, revise el código
sólo con fines ilustrativos.
COMMENT
*
Programa: Rota.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra el uso de las
instrucciones de rotación y desplazamiento.
*
.MODEL TINY
.DATA
dato1 dw 10 ; variable de tipo entero
.CODE
INICIO: ; Punto de entrada al programa
mov ax,1 ; AX=1
mov bx,10 ; BX=10
shl ax,1 ; ax=ax*2
mov cx,3 ; contador igual a 3
shl ax,cl ; ax=ax*8
shr bx,1 ; bx=bx/2
mov cx,2 ;
shr bx,cl ; bx=bx/4
shl dato1,1 ; dato1=dato1*2
mov ax,1 ; ax=1
rol ax,1 ; rotar ax 1 vez
mov bx,-10 ; bx=-10
sal bx,1 ; bx=bx*2
mov ax,4c00h ; Terminar
int 21h ; Salir al dos
END INICIO
END
Instrucciones para la
pila
La pila es un grupo de localidades de memoria que se reservan con
la finalidad de proporcionar un espacio para el almacenamiento
temporal de información.
La pila de los programas es del tipo LIFO (Last In First Out,
Ultimo en entrar, Primero en salir).
Para controlar la pila el microprocesador cuenta con dos
instrucciones básicas: Push (Meter) y Pop (sacar).
El formato de estas instrucciones es el siguiente:
Push operando
Pop operando
Cuando se ejecuta la instrucción Push, el contenido del
operando se almacena en la ultima posición de la pila.
Por ejemplo, si AX se carga previamente con el valor 5, una
instrucción Push AX almacenaría el valor 5 en la
ultima posición de la pila.
Por otro lado la instrucción Pop saca el último
dato almacenado en la pila y lo coloca en el operando.
Siguiendo el ejemplo anterior, la instrucción Pop BX
obtendría el número 5 y lo almacenaría en el
registro BX.
El siguiente ejemplo muestra como implementar la
instrucción XCHG por medio de las instrucciones Push y
Pop. Recuerde que la instrucción XCHG intercambia el
contenido de sus dos operandos.
.COMMENT
Programa: PushPop.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa demuestra el uso de las
instrucciones para el manejo de la pila, implementando la
instrucción XCHG con Push y Pop
*
.MODEL tiny
.CODE
Inicio: ;Punto de entrada al programa
Mov AX,5 ;AX=5
Mov BX,10 ;BX=10
Push AX ;Pila=5
Mov AX,BX ;AX=10
Pop BX ;BX=5
Mov AX,4C00h ;Terminar programa y salir al DOS
Int 21h ;
END Inicio
END
Página siguiente |