leng_ensamblador_ISC - Servidor de Apoyo al Sistema

Anuncio
Lenguaje Ensamblador
Unidad
Temas
1
Fundamentos.
1.1
1.2
1.3
1.4
1.5
1.6
2
Elementos del lenguaje
3
Modularización
Subtemas
Introducción.
1.1.1 Uso y aplicaciones del
lenguaje ensamblador.
1.1.2 Escalabilidad de los
microprocesadores.
1.1.3 Tipos de lenguajes
ensambladores.
1.1.4 Clasificación de Memorias.
1.1.5 Unidades de entrada /
salida.
El microprocesador.
1.2.1 Buses.
1.2.2 Registros.
1.2.3 Modos de direccionamiento.
Interrupciones.
1.3.1 Hardware.
1.3.2 Software.
Estructura de un programa en
ensamblador.
1.4.1 Data segment.
1.4.2 Snack segment.
1.4.3 Code segment.
1.4.4 Instrucciones del programa.
1.4.5 Directivas.
Procedimiento de ensamble,
enlace y ejecución.
Entorno de programación.
2.1 Instrucciones lineales.
2.1.1 Movimiento.
2.1.2 Pila.
2.1.3 Matemáticos.
2.1.4 Ajustes.
2.1.5 Comparación.
2.2 Saltos.
2.2.1 Incondicional.
2.2.2 Condicional.
2.3 Tipos de ciclos.
2.4 Operadores Lógicos.
2.5 Desplazamiento.
2.5.1 Lineal.
2.5.2 Circular.
2.6 Procesos de control.
2.6.1 Banderas.
2.6.2 Cadenas.
2.6.3 Carga.
3.1 Macros.
3.2
4
Programación híbrida.
4.1
4.2
4.3
4.4
4.5
3.1.1 Internas.
3.1.2 Externas.
Procedimientos.
3.2.1 Internos.
3.2.2 Externos.
Directivas para compilación híbrida.
Funciones en ensamblador.
Bloques en ensamblador.
Operadores.
Integrar módulos de ensamblador en
lenguajes de alto nivel.
Unidad1. Fundamentos.
1.1 Introducción.
1.1.1 Uso y aplicaciones del lenguaje ensamblador.
Importancia del Estudio y Uso de Ensamblador
 Ayuda a conocer a detalle cómo trabaja un CPU
 Util para Electrónica y Sistemas
 Desarrolla Habilidades de Programación Avanzada
 Mejores Oportunidades de Empleo en la Industria
Aplicaciones del Lenguaje Ensamblador
 Sistemas embebidos:impresoras, cámaras, autos, armas,
juguetes, etc.
 Tiempo Real: en la industria y manufactura, e.g. adquisición
datos, control robots
 Transporte: barcos, aviones, sondas espaciales, etc.
 Entretenimiento: Graficación, Multimedia, Cine y VideoJuegos
 DSP: Procesamiento de Señales, Voz e Imágenes
 Otras: Medicina, Aeronaútica, Armamento, etc.
Uso de lenguaje ensamblador
Hay algún debate encima de la utilidad del lenguaje ensamblador. En muchos casos,
compiladores modernos pueden rendir lenguajes de alto nivel en el código como eso corre tan
rápido como la mano que escribe en ensamblador.
Sin embargo, algunos cálculos discretos aun pueden darse mas rápidamente corriendo código
en ensamblador, y alguna programación de bajo nivel es simplemente mas fácil de hacer en
ensamblador. Algunas tareas de sistemas-dependientes realizadas por sistemas operativos
simplemente no pueden ser expresadas en lenguajes de alto nivel. Muchos compiladores
también rinden lenguajes de alto nivel en ensamblador antes de compilar completamente,
permitiendo visualizar el código de ensamblador para depurar [debug] y propósito de
optimización.
Muchos dispositivos integrados son también programados en ensamblador a exprimir la
funcionalidad máxima absoluta fuera de los que es frecuente recursos computacionales muy
limitados, aunque esto esta gradualmente cambiando en algunas áreas como mas chips
poderosos volviendo disponible para el mismo mínimo costo.
http://www.geocities.com/SiliconValley/Haven/2037/documentos/Lenguaje_Ensamblador.htm
1.1.2
Escalabilidad de los
microprocesadores.
Al escribir un programa para ser ejecutado por un microprocesador se tienen
tres alternativas: lenguaje de máquina, lenguaje ensamblador y lenguaje de alto
nivel.
Sólo programas escritos en lenguaje máquina pueden ser ejecutados por el
procesador. Los programas escritos en lenguaje ensamblador o en lenguaje de
alto nivel tienen que ser traducidos primeramente a lenguaje máquina a fin de
que puedan ser ejecutados.
Escribir un programa en lenguaje ensamblador requiere de conocimientos
acerca del hardware de la computadora, su conjunto de instrucciones, de sus
reglas y usos.
Un estudio de programación en lenguaje ensamblador puede ser una de las
tareas personalmente más remuneradas y técnicamente más desafiantes que
puedan emprender un ingeniero de software.
El ensamblador básico es la puerta interior de la PC, el principio de lo que se
puede realizar con el lenguaje ensamblador, se encuentra especialmente
diseñado para proporcionar las bases teórico - práctico que le permitirán más
adelante programar el hardware (vídeo, teclado, discos, puertos, etc.)
reconocer y utilizar las memoria del BIOS (Sistema Básico de Entrada y
Salida), aprovechar las estructuras internas del DOS (Sistema Operativo en
Disco), y afirmar y dominar el uso de debugueando codeview y mucho más.
El disponer de herramientas y conocimientos para combinar sabiamente los
lenguajes de alto nivel en diversas configuraciones del hardware le convierten
en el maestro de la máquina, el lenguaje ensamblador será un segundo
lenguaje más potente ya que da al programador acceso directo a registro a
memoria y a la únicas instrucciones orientadas al bit, y es con frecuencia la
única solución a las tareas de programación que prolonga el alcance de la
mayoría de los lenguajes de alto nivel.
Un programa en lenguaje ensamblador producen un código ejecutable de
forma más rápida ya que circunvala el paso de interpretar el lenguaje y el paso
de compilar el lenguaje.
Un programa en lenguaje ensamblador controla al microprocesador en su
propio lenguaje sin la ayuda de comprobaciones del compilador.
HISTORIA DE LOS MICROPROCESADORES.
1971, Intel anunció el primer microprocesador denominado 1001. Este era de 4
bits, construido con tecnología PMOS. Tenía 45 instrucciones, y ejecutaba
60,000 operaciones por segundo.
1972, Intel introdujo el microprocesador 8008, con longitud de palabra de 8 bits;
implantado con tecnología PMOS. Tenía 48 instrucciones, ejecutaba 30,000
operaciones por segundo y direccionaba 16 K bytes de memoria. Requería casi
de 20 circuitos de soporte. El microprocesador contenían compuertas SSI
(Small Scale Integration) y MSI (Medium Scale Integration).
1974, Intel crea el microprocesador 8080, de 8 bits. El 8080 tenía 78
instrucciones, con una velocidad de operación diez veces mayor que la del
8008 y direcionaba hasta 64 Kbytes de memoria. La tecnología de fabricación
usada fue la NMOS y gran parte de la lógica de soporte se incluyo en el mismo
circuito de microprocesador; por lo que fue posible construir un sistema con
sólo seis circuitos integrados.
1974, Motorola crea un microprocesador de 8 bits con 72 instrucciones, el
6800. Al mismo tiempo apareció una familia de circuitos periférico diseñados
especialmente para conectarse al microprocesador.
1975, Mostechnology anuncio dos microprocesadores, el 6501 que era
compatible pata a pata con el 6800 y el 6202, cuyo circuito integrado incluía,
además de un 6501, toda la circuitería para generar la señal de reloj. Hasta
entonces, la señal de reloj se había generado en circuitos externos al
microprocesador.
1976, Zilog introdujo el Z-80, un microprocesador NMOS de 8 bits, requería una
fuente de alimentación de 5 volts y toda la circuíteria de soporte estaba incluida
en el circuito integrado. Contenía 158 instrucciones.
Junto con el microprocesador Z-80 (Z80 CPU) Zilog introdujo varios
circuitos periféricos, tales como el controlador de puertos en paralelos
(Z80 PIO), el controlador de puertos en serie (Z80 SIO) y el circuito
timer/contador (Z80 CTC).
1977, Intel anunció el microprocesador 8085, con longitud de palabra de 8 bits,
este combinaba el 8080, el circuito de reloj y el controlador del sistema en un
solo circuito integrado. Fabricado con tecnología NMOS, y requería un voltaje
único de 5 volts.
El 8085 se optimizo para que pudiera formar un sistema completo
utilizando dos circuitos periféricos especial, uno de ellos con memoria
RAM, puertos de Entradas y Salida y timer (8155 u 8156) y el otro con
memoria ROM o EPROM y puertos (8355 u 8755).
1978, nace la tercera generación de microprocesadores cuando Intel desarrolla
el 8086. Este fue un diseño más avanzado con características nuevas. Además
Intel desarrollo el microprocesador 8088 como una variación al 8086.
Casi al mismo tiempo apareció un primo del 8088/808; la pastilla del
coprocesador matemático de números reales 8087. Este procesador de datos
numéricos estaba dedicado a alta velocidad y cálculos matemáticos de alta
precisión.
En 1984 se desarrolla el microprocesador 8086, este es compatible con el
8088/8086, soportaba diferentes tipos de datos muy potentes como cadenas
BCD y formatos en puntos flotantes.
Posteriormente se introdujo el 80186, una versión altamente integrada del
8086, es un microprocesador de 16 bits.
El 80286, es una versión mejorada del 8086, que contiene una unidad de
administración de memoria y direcciona a una memoria de 18 Mbytes. Además
la velocidad del reloj fue aumentada.
Otro ingreso de Intel es el 80386, con un bus de datos externos de 32 bits del
80386, doble que el del 80286, puede direcionar 4 gigabytes de memoria.
Uno de los últimos desarrollos de Intel, es el procesador Pentium II, que es el
procesador más potente de la familia X86, estos cuentan con una velocidad de
233, 266 y 300 Mhz. Añadido con tecnología MMX y un caché LI de 32 K, y
está compuesta por 12 sistemas MMX a 200 Mhz de II fabricantes. Cada
sistema tiene por lo menos 32 MB en RAM, un disco de 2GB o superior, una
unidad de CD-ROM 6X o más rápido, un sistema de sonido de 16 bits y una
tarjeta gráfica super VGA.
1.1.3
Tipos de lenguajes ensambladores.
Este lenguaje da la facilidad y las herramientas necesarias para tomar el
control de todo lo que la PC puede realizar físicamente. Como resultado de
operaciones muy básicas suministradas por el ensamblador que realiza tareas
simples de transferencia de datos y operaciones lógicas, una página de
códigos en lenguaje ensamblador palidece en comparacion con una página de
código en lenguaje de alto nivel.
Hablar del lenguaje máquina requiere comprender muchos conceptos extraños
para los programadores de alto nivel, el programador de lenguaje ensamblador
debe considerar la segmentación de memoria; cuando hay control directo del
acceso de memoria deben ser tomadas decisiones al minuto, se debe decidir el
tamaño y tipo de cada dato, muchas de estas consideraciones son únicas a la
programación en lenguaje ensamblador.
ENSAMBLADOR.
Un ensamblador es un software que traduce un programa en memoria escrito
en mnemónicos por el usuario, a lenguaje máquina que pueda ser ejecutado
por el microprocesador. Al programa en mnemónicos se le llama PROGRAMA
FUENTE y al programa en lenguaje máquina se le denomina PROGRAMA
OBJETO. Por lo tanto, la entrada al ensamblador es un programa fuente y la
salida es un programa objeto.
FUNCIONES DEL ENSAMBLADOR.
A demás de su tarea principal que es traducir mnemónicos a lenguaje máquina,
un ensamblador generalmente realiza las siguientes funciones:
o
o
o
o
o
o
Permite al usuario asignar nombres a localidades de memoria,
constantes numéricas, dispositivo de E/S y una secuencia de
instrucciones.
Acepta datos o direcciones en varios sistemas numéricos
(decimal y hexadecimal) y las convierte en binario.
Ejecuta algunas operaciones aritméticas en expresiones como
parte del proceso de ensamblador.
Permite al usuario designar las áreas de memoria donde será
colocados el programa a los datos en el momento de ejecución.
Proporciona la información requerida para incluir otros programas
o subrutinas de biblioteca dentro del programa que sé esta
realizando.
Permite al usuario controlar el formato del listado del programa
resultante del ensamblador.
El lenguaje ensamblador utiliza mnemónicos para representar los códigos de
operación de las instrucciones y símbolos alfanuméricos para representar las
direcciones y los datos del programa. Entonces el programa se puede escribir
como:
MOV AX, (150)
MOV BX, AX
MOV AX, (151)
ADD AX, BX
MOV (152), AX
Las direcciones y los datos del programa anterior se expresaron directamente
en hexadecimal. A continuación se muestra el mismo programa utilizando todas
las propiedades del lenguaje ensamblador.
MOV AX, NUM1
MOV BX, AX
MOV AX, NUM2
ADD AX, B
MOV SUMA, AX
La ventaja de utilizar nombres simbólicos en las instrucciones, en lugar de su
valor numérico, es facilitar la escritura del programa, y también simplifica la
inserción y eliminación de instrucciones, haciendo más fácil el
redireccionamiento.
La desventaja de un programa en lenguaje ensamblador, es que requiere un
programa especial llamado ENSAMBLADOR, que se encarga de traducir los
mnemónicos y los símbolos alfanuméricos a lenguaje máquina. Además sigue
siendo necesario un conocimiento detallado de la arquitectura del
microprocesador.
El lenguaje ensamblador es una variante legible para el ser humano del
lenguaje máquina que usan las computadoras para ejecutar programa. Al
mismo tiempo la mejor manera de comunicarse con la PC y con el lenguaje
máquina de programación que utilice.
El lenguaje ensamblador resulta indispensable cuando se desea escribir
programas que controlen las E/S de la PC, agregar nuevas interfaces de E/S,
escribir rutinas que aprovechen y maximicen el uso del hardware y en general
realizar cualquier tarea que no pueden llevar acabo los demás lenguajes de
programación.
El lenguaje ensamblador le brinda la oportunidad de conocer más afondo la
operación de su PC esto le permite implementar software o hardware de una
manera más consiente. El lenguaje ensamblador hace que se conserve el
control total de lo que desea hacer su PC.
Una de las mayores importancias del ensamblador es que uno puede optimizar
al máximo sus programas (tanto tamaño, como velocidad de ejecución). Otra
importancia es la gran velocidad a la que ejecuta el código.
El lenguaje ensamblador permite a los ingenieros de software hacer interfaces
con el sistema operativo y les da control directo de las operaciones de entrada
y salida a monitores, impresoras, y a los importantes dispositivos de memoria
de disco duro/flotante.
Los programadores de aplicaciones con frecuencia tienen que hacer también
interfaces directamente con el sistema operativo. Estas rutinas se escriben en
lenguaje ensamblador.
El lenguaje ensamblador es simplemente una representación simbólica del
lenguaje máquina asociado, lo cual permite una programación menos tediosa
que con el anterior. Sin embargo es necesario un conocimiento de la
arquitectura mecánica subyacente para realizar una programación efectiva en
cualquiera de estos niveles de lenguaje.
La mayoría de los ensambladores son ENSAMBLADORES DE DOS ETAPAS
(two-pass Asemblers).
La PRIMERA ETAPA determina la dirección de memoria en la cual es
ensamblado el primer byte de cada instrucción y genera una tabla para los
valores de todos los nombres simbólicos y etiquetas definidos en el programa.
El ensamblador posee una tabla de códigos de operacióncon una entrada por
cada código de operación, cada entrada contiene el mnemónico de la
instrucción, su equivalente en lenguaje máquina y el número de bytes de la
intrucción.
También el ensamblador tiene un Contador de localización (Location Counter,
LC), el cuál al inicio se carga con 0 ó con el valor especificado por una directiva
ORG, ésta corresponde a la dirección inicial u origen del programa y se le
asigna el primer byte de la primera instrucción.
Si un programa tiene una etiqueta, esta se añade a la tabla de símbolos y se le
asocia el valor conteniendo del LC en ese momento.
El código de operación de la instrucción se extrae de la tabla de código de
operación incrementando el contador de localización igual al número de bytes
de la instrucción. Esta etapa termina cuando el ensamblador detecta la
directiva END.
En la SEGUNDA ETAPA, el ensamblador hace un recorrido por el programa,
utilizando la tabla de símbolos de los códigos de operación, sustituye el
mnemónico de cada instrucción por su equivalente en el lenguaje de máquina.
1.1.4
Clasificación de Memorias.
Las terminales de entrada/salida de un procesador proporcionan un modo
eficiente de comunicación entre el sistema central y el ambiente exterior. Los
programas y los datos, deben entrarse al computador para el procesamiento y
los resultados deben registrarse o exhibirse para el usuario. Para que esto
suceda, la información pasa a través de la memoria central.
MEMORIA CENTRAL
También denominada memoria principal, es la parte de la CPU de una
computadora donde están almacenadas las instrucciones y los datos
necesarios para que un determinado proceso pueda ser realizado.
La memoria central está constituida por multitud de celdas o posiciones de
memoria, numeradas de forma consecutiva, capaz de retener mientras la
computadora esta conectada.
La memoria es el centro de actividad, el lugar en donde todo se mantiene
cuando se está trabajando. La memoria proporciona un lugar donde pueden
realizarse los cálculos, para la memoria de la computadora no hay diferencia
entre programas y datos, ambos son información que debe ser registrada,
almacenada o manipulada.
Esta memoria consiste en una serie de microcircuitos que sirven de soporte
generalmente transitorio de la información. Sus características principales son:




Gran rapidez.
Componentes fijos.
Capacidad mediana.
Reutilizable y de acceso directo.
Su velocidad de proceso se mide en microsegundos (millonésima de segundo),
nanosegundo (milmillonésima de segundo) e incluso picosegundos
(billonésima de segundo).
Es una memoria de acceso directo, puede accederse a una de sus celdas con
sólo conocer su posición, para esta memoria el tiempo de acceso es más corto
que las memorias auxiliares, por tanto, los datos que manejan los procesos
deben residir en ella en el momento de su ejecución.
La memoria central tiene asociados 2 registros para la realización de
operaciones de lectura o escritura y un dispositivo encargado de
seleccionar una celda de memoria en cada operación de acceso sobre la
misma.
 REGISTRO DE DIRECCIÓN DE MEMORIA (RDM). Contiene la dirección de
memoria donde se encuentra o va a ser almacenada la información
(instrucción o dato), tanto si se trata de una lectura como de una escritura.
 REGISTRO DE INTERCAMBIO DE MEMORIA (RIM). Si se trata de una
operación de lectura, el RIM es quién recibe el dato de la memoria señalado
por el RDM, para su posterior envío a uno de los registros de la Unidad
Aritmética y Lógica. Si se trata de una operación de escritura, la operación a
grabar tiene que estar en el RIM, para que desde el se transfiera a la posición
de memoria indicada por el RDM.
 SELECTOR DE MEMORIA (SM). Es el registro que tras una orden de lectura
o escritura conecta la celda de memoria cuya dirección figura en el RDM con el
RIM, posibilitando la transferencia de los datos en un sentido o en otro.
La Memoria Central suele ser direccionable por octeto o Byte, por tanto; una
celda o posición de memoria contiene 8 bits. Una de las características
fundamentales de una computadora es su Capacidad de Memoria Interna
(Memoria Central), la cual se mide en un múltiplo del Byte denominado
Kilobyte, Kbyte, KB O k, y que equivale a 1024 bytes (1024 = 210). Otro
múltiplo utilizado ampliamente en los últimos tiempos es le Megabyte o mega
que equivale a 1024 * 1024 Bytes.
Las computadoras utilizan 2 tipos de memoria interna:
1. MEMORIA DE SOLO LECTURA (READ ONLY MEMORY: ROM). Esta
almacena ciertos programas e información que necesita la computadora. Estas
instrucciones están grabadas permanentemente en el chip de ROM y no
pueden ser modificados por el operador, por eso es de sólo lectura. Se
conocen también como memoria No Volátil por que no desaparece o se borra
cuando se desconecta la electricidad.
Las instrucciones básicas que se necesitan para arrancar una computadora
están almacenadas en ROM. Algunos programas de utilería y paquetes de
software también lo están.
Las posiciones altas de la memoria superior son:



ROMBIOS
ROM DE INICIO
ROM EXTENDIDA
Existen otras variedades que permiten algunas manipulaciones:

PROM: Permite programarse una sola vez, una vez decididas sus
características e instalada, se convierte en una ROM normal.

EPROM: Puede borrarse y reprogramarse varias veces, para ello se
necesitan técnicas especiales de borrado y escritura.
2. MEMORIA DE ACCESO ALEATORIO (RANDOM ACCESS MEMORY:
RAM). Aquí también podemos almacenar ciertos programas para el
funcionamiento de la computadora. Sin embargo, en RAM el usuario puede
cambiar la información, almacenarla o borrarla. La capacidad de la RAM afecta
la forma en que se corren los programas del software y la cantidad de datos
que pueden procesarse. Cuando más fácil de usar sea un programa tanta más
RAM necesitará generalmente. La RAM es una memoria volátil, a menos que
se guarden en discos, se pierde cuando la computadora se desconecta excepto
en algunos que están provistos de pilas especiales para mantener el contenido
de la RAM.
Cuando se crea un programa o un documento de aplicación, el programa que
carga y los datos que se introducen mediante el teclado son almacenados en
forma temporal en la RAM. El término aleatorio proviene de la forma en que la
computadora localiza o da acceso a los datos que se encuentran en la
memoria. Si se pasa por todos los datos para encontrar alguna información
deseada, esto es acceso secuencial. Si se brinca todos los datos y selecciona
directamente la información deseada, sin pasar por los otros datos, a esto se le
llama Acceso Aleatorio o Directo.
La RAM es un dispositivo de estado sólido que no tiene partes en movimiento.
Se puede tener acceso a los datos de la RAM a velocidades electrónicos
comparables a la velocidad de la luz. A la memoria RAM también se le llama
memoria principal y es un almacenamiento temporal.
Todos los programas y datos introducidos a un dispositivo de entrada (teclado)
o a una memoria magnética (disco) se debe transferir a la RAM antes que se
puedan ejecutar los programas o procesar los datos. La capacidad en RAM se
define en función del número de caracteres que puede almacenar.

Memoria Convencional. Se le denomina así a la RAM comprendida
entre los 0 y 60 KB.

Memoria Superior. Se le llama así al resto de la memoria RAM hasta 1
MB, es decir al espacio comprendido entre los 640 y 1.024 B, es decir a
los 384 KB.

Memoria Extendida. Es la superior a 1 MB, que llegará a los 16 MB, en
los 286 (AT) y a4.096 MB o 4 GB, en los 386 y 486.
Estas dos últimas clases de memorias RAM se subdividen en otros tipos:

Memoria Expandida, Shadow y de Vídeo (la superior) y en memoria alta
(extendida), dependiendo del tipo de procesador.
Cada memoria está formada por bloques de octetos consecutivos, de tamaño
de 16 bytes o un múltiplo de ese número (16, 32, 48, 64 octetos, etc.).
SALIDA.
Son los dispositivos cuya misión es la de recoger y proporcionar al exterior los
datos de salida de cada uno de los trabajos que se realicen en el sistema.
También se denominan Periféricos o Unidades de Salida. La computadora
comunica sus resultados al usuario; por ejemplo, Desplegando la información
en un monitor o imprimiéndola. Estos dispositivos incluyen:





ENTRADA.
Monitores
Impresoras
Plotters
Graficadores
Son los dispositivos periféricos que permiten introducir la información a la
computadora para su procesamiento. Algunos de estos dispositivos son:







Teclado
Mouse
Tabletas gráficas
Lápiz óptico
Entrada de Voz
Pantallas sensibles al tacto
Lectores ópticos
ENTRADA/SALIDA
Son dispositivos que efectúan tanto tareas de entrada como de salida, estos
incluyen:



Discos duros
CD´s
Discos flexibles
1.1.5 Unidades de entrada / salida.
 Periféricos: Unidades o dispositivos externos
que se conectan a la computadora central
CPU-Mem, e.g. ratón, monitor, disco-duro,
CD, etc.
 Interfaz: Es el medio que permite conectar
un periférico a la computadora, e.g.
conector, puerto, tarjeta, etc. Existen
diferentes tipos de interfaces:
 Puerto Paralelo (LPT): cable corto, grueso que
transmite arriba de 16 bits, e.g. impresora, discos
externos, etc.
 Puerto Serie (COM): cable largo, delgado que
transmite 1 bit, e.g. mouse, teclado, modem, etc.
 Puertos USB, FireWire: tecnología veloces y
compactas que posiblemente reemplacen al cable
serie/paralelo
 Interfaz IDE, SCSI, PCI, EISA: interfaces de bajo
nivel para conectar tarjetas y dispositivos internos,
e.g. discos duros, CD, video, etc.
http://pantera.itchihuahua.edu.mx/apacheco/expo/view.
php?f=asm_11#page9
1.2 El microprocesador.
Un microprocesador debe contener al menos: una unidad de control, unidad de
aritmética y lógica y algunos registros.
Los componentes internos de un microprocesador son:
a) REGISTROS GENERALES
b) REGISTROS APUNTADORES (ESP Y EBP).
c) REGISTROS INDICES (ESI Y EDI).
d) REGISTRO DE SEGMENTOS (SS, CS, DS, ES.)
e) REGISTRO APUNTADOR DE INSTRUCCIONES (IP).
f) REGISTRO DE ESTADO (BANDERAS)
g) COLA DE INSTRUCCIONES
h) UNIDAD DE CONTROL DE LA UNIDAD DE EJECUCIÓN
i) BUSES INTERNOS
j) UNIDAD ARITMETICA Y LOGICA (ALU)
g) COLA DE INSTRUCCIONES
Una cola cuya abreviatura es Q de "queue", es una línea de espera como la
que forman en la caja del supermercado. Algunos de los microprocesadores de
16 bits como el 8086/8088 del Intel o Motorola MC 68000 utilizan tales líneas
de espera para sus instrucciones. Dicho de otra manera sus instrucciones que
han de ejecutarse llegan al microprocesador antes de lo necesario y "esperan"
en una cola de instrucciones en este sistema, poseen la ventaja de que cada
instrucción puede extraerse de memoria mientras otras se están ejecutando
reduciéndose en consecuencia el tiempo de proceso, por ejemplo las
instrucciones que incluyen directamente a la velocidad de aquellas otras que
utilizan datos de los registros de la CPU, las colas de instrucciones son
normalmente cartas de 496 octetos en concreto la del 8086 es de 6 octetos,
(tres palabras y la del 8088 es de 4 octetos). La cola de instrucciones es de un
área de almacenamiento de tipo PEPS (Primero en entrar, primero en salir)
para instrucciones decodificadas y operandos ya disponibles.
h) UNIDAD DE CONTROL DE LA UNIDAD DE EJECUCIÓN
La función principal de la UC es dirigir la secuencia de pasos de modo que la
computadora lleve a cabo un ciclo completo de ejecución de cada una de las
intrusiones del programa. Utiliza señales de reloj, por lo que se considera que
el microprocesador es un dispositivo síncrono. Su actividad es cíclica y
consiste en la búsqueda y obtención de datos e instrucciones, y en la ejecución
secuencial de éstas últimas.
El corazón de la unidad de control lo constituye el GENERADOR DE CICLO DE
LA MAQUINA (GCM), que se encarga de producir las señales de control,
derivándolas de un reloj u oscilador maestro.
Pasos para ejecutar una instrucción cualquiera:
a) Ir a la memoria y extraer el código de la siguiente instrucción. Este paso se
llama "ciclo fetch".
b) Decodificar la instrucción ya leída.
c) Ejecutar la instrucción.
d) Prepararse para leer la siguiente casilla de memoria y continuar con el paso
a).
Las principales funciones de esta unidad son:
a) Leer e interpretar las instrucciones del programa.
b) Dirigir la operación de los elementos internos del procesador.
c) Controlar el flujo de datos y programas que entran y salen de RAM.
Para realizar su función consta de los siguientes elementos:





Registro de control de secuencia (RCS). También denominado
contador de programa (CP), contiene permanentemente la dirección de
memoria de la próxima instrucción a ejecutar. Si la instrucción que se
esta ejecutando en un instante determinado es de salto o de ruptura de
secuencia, el RCS tomara la dirección de la instrucción que se tenga
que ejecutar a continuación, esta instrucción la traerá de la propia
instrucción en curso.
Registro de instrucción (RI). Contiene la intrusión que se esta
ejecutando a cada momento. Esta instrucción llevara consigo el código
de operación (CO), ación de que se trata y en su caso los operandos o
las direcciones de memoria de los mismos.
Decodificador (D). Se encarga de extraer y analizar el código de
operación de la instrucción en curso (que está en RI) y dar señales
necesarias al resto de los elementos para su ejecución.
Reloj (R). Proporciona una sucesión de impulsos eléctricos a intervalos
constantes (frecuencia constante), que marca los instantes en que se
han de comenzar los distintos pasos de que consta cada instrucción.
Secuencia (S). En este dispositivo se encargan ordenes muy
elementales (microordenes), que sincronizadas por los impulsos del
reloj, hacen que se vaya ejecutando poco a poco la instrucción que esta
encargada en el RI.
j) UNIDAD ARITMETICA Y LOGICA (ALU)
La unidad de aritmética y lógica es un circuito digital que realiza un conjunto de
micro-operaciones aritméticas y lógicas.
Operaciones que realiza una ALU:
1. Suma aritmética.
2. Funciones lógicas AND, OR y XOR.
3. Complemento.
4. Rotación hacia la izquierda o derecha.
Esta unidad es un grupo de circuitos electrónicos encargada de realizar las
operaciones elementales de tipo aritmético (+, -, *, /) y de tipo lógico
(comparaciones), también hace comparaciones alfabéticas, por ejemplo; Soto,
Sánchez.
Para realizar su función consta de los siguientes elementos:




Banco de Registros. (BR): Está constituido por 8, 16, 32 registros de
tipo general que sirve para situar datos antes de cada operación, para
almacenar datos intermedios en las operaciones y para operaciones
internas del procesador.
Circuito de Operadores. (CIROP): Compuesto de uno o varios circuitos
electrónicos que realizan operaciones elementales aritméticas y lógicas
(sumador, complementador, desplazador, etc.).
Registro de Resultados. (RR): Se trata de un registro especial, en el
que se depositan los resultados que producen los circuitos operadores.
Señalizador de Estado. (SE): Registro con un conjunto de biestables en
los que se deja constancia de algunas condiciones que se dieron en la
última operación realizada.
1.2.1
i)
Buses.
BUSES INTERNOS (DATOS, DIRECCIONES).
BUS. Es un canal o ruta común de comunicación entre dispositivos del
hardware, ya sea internamente entre componentes del computador o
externamente entre estaciones de una red de comunicaciones. Los buses
se asemejan a una carretera por la que circulan los bits físicamente, los
buses son varios hilos paralelos, uno para la transmisión de cada bit.
Cuando la arquitectura del bus es utilizado en un computador, el procesador
o procesadores, los bancos de memoria y las unidades de control periférica
están todos interconectados mediante el bus. El bus está dividido en dos
canales, uno para seleccionar donde esta localizado el dato (bus de
direcciones) y otro para transferir el dato (bus de datos).
BUS DE DATOS. Circulan los datos con los que va a trabajar el ordenador,
debe estar conectado a la memoria principal, puesto que en ella se encuentran
almacenados los datos, al banco de registro y por supuesto a la unidad
aritmética y lógica, el bus de datos tiene 8 conectores y es capaz de transportar
8 señales en paralelo, esto significa que el bus de datos puede llevar unidades
de información de 8 dígitos binarios, sólo una unidad cada vez.
BUS DE DIRECCIONES. Se emplea para transmitir la información que ha de
reaccionar la memoria. Si el bus de direcciones tiene 16 hilos, se podrá
direccionar Z16 direcciones de memoria, es decir, se puede acceder a
cualquier posición de memoria de 64 KB. Si se considera la cuestión de forma
inversa se precisan dos palabras de 8 bits para conseguir una dirección de
memoria. Llevar señales de control especial que provocan la selección de la
información a través de la computadora. Esta información se utiliza para
distinguir a la vez entre varios dispositivos de E/S y las miles de celdas de la
memoria de la computadora.
EL BUS DE CONTROL: Sincroniza el sentido de la transferencia de
información en el bus de datos (hacia adentro o hacia afuera). Cada una de las
señales del bus de control son unidireccionales.
1.2.2
Registros.
a) REGISTROS GENERALES
Los registros de propósito general son capaces de soportar operandos de
datos de1, 8, 16 y 32 bits, estos registros también soportan operandos de
direcciones de 16 y 32 bits. Los 8 registros son AX (acumulador), BX (en base),
CX (contador), DX (datos), SP (puntero de pila), BP (puntero base), SI (índice
fuente) y DI (índice destino).
Para acceder a los 32 bits de un registro todas las referencias a registros debe
comenzar con la letra "E". Cada uno de los 8 registros de propósito general
pueden ser compuestos en sus equivalentes de 16 bits de 8086 bits/80286
referenciando los registros sin usar el prefijo E.
REGISTRO EAX (Acumulador). Generalmente se usa para almacenar
resultados de operaciones aritméticas o lógicas, lectura o escritura desde o
hacia los puertos y como un área de memoria principal temporal (SCRATCH
PAD). También se direcciona como AX, AH, o AL.
REGISTRO EBX ( Base). Sirve como registro apuntadores base o índice.
Conserva la dirección base (desplazamiento) de los datos que hay en la
memoria o la dirección base de una tabla de datos. También se direcciona
como BX, BH, o BL.
REGISTRO ECX (Contador). Se utiliza constantemente en operaciones de
interacción, como un contador que automáticamente se incrementa o
decrementa de acuerdo con el tipo de cada instrucción usada. También es
usado para corrimientos (CL) y rotaciones y ciclos y para las operaciones de
cadena y un contador. También se direcciona como CX, CH, CL.
REGISTRO EDX ( De Datos). Comúnmente se usa como fuente para el
acceso de datos. También se direcciona como DX, DH y DL.
b) REGISTROS APUNTADORES (ESP Y EBP).
La dirección física de cualquier elemento dado en un segmento seleccionado
se obtiene por la combinación de la dirección del segmento y el
desplazamiento, este desplazamiento puede estar contenido en uno de los
registros puntero, base o índice.
Las operaciones de la pila son facilitadas por el sector del segmento de pila
(SS) y el par de registros de puntero de pila (SP) o puntero base (BP).
REGISTRO ESP O APUNTADOR DE PILA. Apunta a un área específica de
memoria que sirve para almacenar datos bajo la estructura LIFO (LAST, IN,
FRIST OUT) mejor conocido como PILA STACK. Esto ocurre cuando se
ejecutan las instrucciones PUSH y POP cuando se llama (CALL) o se regresa
(RET) de una subrutina de un programa principal. También se direcciona como
SP.
REGISTRO EBP O BASE. Se usa para manipular la pila sin afectar el registro
de segmentos SS, así como para direccionar una matriz de datos en una pila
de memoria. También se direcciona como BP.
c) REGISTROS INDICES (ESI Y EDI).
Manipulaciones de datos más complicadas pueden obtenerse utilizando los
registros índice fuente (ESI) e índice destino (EDI) junto al segmento de datos
actualmente activo.
REGISTRO SI. Se emplea para direccionar datos de fuente en forma indirecta
para utilizarlos con las instrucciones de cadenas o arreglos.
REGISTRO DI. Se emplea para direccionar datos destino en forma indirecta
para utilizarlos con las instrucciones de cadenas o arreglos.
d) REGISTRO DE SEGMENTOS (SS, CS, DS, ES.)
Un segmento es un módulo de código que puede ser accesible
simultáneamente con los demás. El microprocesador 80386 y 80486 contienen
6 registros segmento de 16 bits, estos mantienen los valores del selector en las
posiciones de memoria actualmente direccionables. En modo de dirección real,
un segmento puede variar desde un byte hasta un tamaño de segmento
máximo de 64 Kb.
La figura muestra la representación gráfica de los registros de segmento.





CS (código). El segmento de código es una sección de la memoria que
tiene los programas y procedimientos utilizados por los programas. Este
define la dirección inicial de la sección de memoria que tiene el código.
El segmento de código direcciona a 4Gbytes en el 80386 y 80486.
DS (datos). Es una sección de memoria que contiene la mayor parte de
los datos utilizados por un programa.
ES (extra o adicional). El segmento extra o adicional de datos lo utilizan
algunas instruucciones para cadenas.
SS (pila). El segmento de pila define la superficie de la memoria
utilizada para la pila. La ubicación del punto inicial de entrada a la pila,
se determina por el registro apuntador de la pila.
FS y GS. Estos registros de segmento adicionales están disponibles en
los microprocesadores 80386 y 80486 a fin de contar con dos
segmentos adicionales de memoria para acceso con los programas.
e) REGISTRO APUNTADOR DE INSTRUCCIONES (IP).
El puntero de instrucciones (IP) contiene desplazamiento necesario para
direccionar la siguiente instrucción que se va a ejecutar en el segmento de
código actualmente activo. Para formar la localidad real de la siguiente
instrucción se suma el contenido de IP con CS (por) 10H. En general un
puntero de 32 bits a la siguiente instrucción secuencial del programa.
REGISTRO IP (INSTRUCCIÓN POINTER). Apunta a la siguiente instrucción
que será ejecutada en memoria.
f) REGISTRO DE ESTADO (BANDERAS)
Las banderas o señalizadores indican la dirección del microprocesador a la vez
que controlan su movimiento. Los bits de banderas cambian después de
ejecutar muchas de las instalaciones aritméticas y lógicas. En la figura se
muestran claramente.
Registro de banderas
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
AC VM RF
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
NT IOP IOP OF DF IF TF SF ZF
AF
PF
0
CF
Las banderas indican la condición del microprocesador a la vez que controlan
su miento. Los bits de bandera cambian después de ejecutar muchas de las
instrucciones aritméticas y lógicas.










El señalizador de arrastre (CF) se pone a 1 cuando se genera un
arrastre en una operación aritmética realizada sobre un operando de 8 ó
16 bits. En cualquier otro caso, está a 0 CF también se utiliza en
instrucciones de desplazamiento y rotación y contiene el bit desplazado
o rotado fuera del registro.
El señalizador de paridad (PF) se utiliza principalmente para
aplicaciones de comunicaciones de datos y se pone a 1 para generar
paridad impar a 0 para generar paridad par.
El señalizador de arrastre auxiliar (AF) se utiliza en aritmética BCD
para indicar si ha habido arrastre o préstamo en los dígitos
correspondientes a los 4 bits menos significativos de un valor BCD.
El señalizador de cero (ZF). Indica que el resultado de una operación
aritmética o lógica es cero. Si ZF=1, el resultado es cero, y si ZF=0 el
resultado no es cero.
El señalizador de signo (SF) se pone a 1 para resultados negativos y a
0 para resultados positivos. Toma el valor que tiene el registro más
significativo.
El señalizador de rebose (OF) indica si una operación ha generado
arrastre en el bit de orden superior del resultado pero no de un arrastre
de otro bit diferente del orden superior.
Tres de los once señalizadores (TF, IF y DF) se utilizan para controlar
ciertas operaciones del procesador.
El señalizador de trampa - TAP (TF). Cuando sé inicializa pone al
microprocesador en modo de paso simple y habilita la depuración de un
programa.
El señalizador de habilitación de interrupción (IF) habilita
interrupciones externas cuando se pone uno, y las habilita cuando se
pone cero.
La dirección de las operaciones con cadenas está controlada por el
señalizador de dirección (DF). Con DF a cero, si y/o DI son
incrementados automáticamente con DF a 1, si IO, DI son
decrementados automáticamente.




Los señalizadores IOP y NT son dos señalizadores nuevos no
suministrados anteriormente y solamente son usados cuando el
microprocesador está en modo protegido, el señalizador de niveles E/S
de privilegio (10 P) se utiliza para garantizar que una instrucción realiza
todas aquellas operaciones que está autorizada a realizar. El
señalizador de tareas (NT) se utiliza para indicar si la ejecución de la
tarea actual está anidada en otras tareas. Si NT está a uno, la tarea
actual anidada tiene un enlace a la tarea previa.
El señalizador RF (de resumen) se usa junto con los "break points" del
registro de operación a pasos simples. Cuando RF está en uno todos los
fallos de depuración se ignoran en la siguiente instrucción, entonces, RF
se pondrá automáticamente a cero (RESET) cuando complete con éxito
cada instrucción.
El VM (señalizador modo virtual) si VM está a uno y el 80386 está en
modo protegido, el microprocesador conmutará a la operación en modo
virtual del 8086, haciendo que todas las operaciones de segmentos se
ejecuten como si estuvieran corriendo en un 8086.
Señalizador (AC) comprobación de alineación.
1.2.3
Modos de direccionamiento.
TECNICAS DE DIRECCIONAMIENTO.
Una instrucción del 80286/80386/80486 no solamente contiene información
sobre la operación en particular a realizar, sino que también incluye las
especificaciones para el tipo de operandos a manipular, así como también la
posición de estos.
La manera en que los operandos se escogen durante la ejecución del
programa depende del modo de direccionamiento de la instrucción. El modo de
direccionamiento especifica una regla para interpretar o modificar el campo de
dirección de la instrucción antes de que el operando sea en realidad
referenciado.
Se empleará la instrucción MOV (mover datos) para describir los modos de
direccionamiento de datos. En el ejemplo se ilustra la instrucción MOV y define
la dirección del flujo de datos a la fuente a la derecha y el destino a la
izquierda.
MOV
MOV
destino, fuente
AX,
BX
Modo Implicado
En este modo los operandos son especificados implícitamente en la definición
de la instrucción. Por ejemplo, la instrucción “complemente el acumulador” es
una instrucción de modo implicado debido a que el operando en el registro
acumulador está implicado en la definición de la instrucción.
DIRECCIONAMIENTO DE DATO INMEDIATO
El termino inmediato significa que los datos siguen inmediatamente al código
hexadecimal de operación en la memoria. El direccionamiento inmediato actúa
en byte o palabra de datos. A continuación se muestra el funcionamiento del
direccionamiento de dato inmediato.
MOV
MOV
MOV
MOV
AH,00
AL,04
AX,0FFFFFH
AX,302
;AH se pone a cero (00)
;AL se carga con 0000 0100 en binario
En este modo él operando es especificado en la instrucción misma. Esto es,
una instrucción de modo inmediato tiene un campo de operando en vez de un
campo de dirección.
En la modalidad inmediata, el operando se incluye como parte de la instrucción.
Por ejemplo MOV AX, 5. Aquí el número 5 forma parte de instrucción en su
totalidad, en otras palabras, el número se especifica como una constante
numérica en la misma instrucción y no hay necesidad de accesar la memoria,
la instrucción mueve el valor de 5 al registro AX.
Ejemplos:
MOV AX, 60
MOV BX, 01A
MOV AX, 083
MOV CX, 2BC
MOV DX, 0123
DIRECCIONAMIENTO DIRECTO
Con el direccionamiento directo, el desplazamiento del segmento de operando
está contenido en la instrucción como una cantidad de 16 bits. Este
desplazamiento se suma al contenido desplazado del registro del segmento de
datos (DS) y se devuelve a la EA de 20 bits, o dirección física real.
Habitualmente, el operando de direccionamiento directo es un rótulo.
Ejemplo:
MOV AX, MYDATA
MYDATA
CONT DIR.
0005
0004
FF
0003
00
0002
0001
0000
AX
1111111100000000
En la mayor parte de las instrucciones se puede emplear el modo de
direccionamiento directo de datos, el cual se aplica en muchas instrucciones en
un programa típico. Hay dos formas básicas de direccionamiento directo de
datos (1) direccionamiento directo y (2) direccionamiento por desplazamiento;
en este caso el direccionamiento directo solo se permite con una instrucción
MOV que transfiera datos entre una localidad en la memoria, situada dentro de
datos y un registro AL (8 bits), AX (16 bits) o EAX (32 bit). Esta instrucción
siempre tiene una longitud de 3 bytes.
Ejemplo: La instrucción MOV CX, LIST copia el contenido tamaño palabra de la
localidad LIST de la memoria y lo coloca en el registro CX.
MOV AX, DDDW
MOV BX, DDDY
MOV AX, DDDU
DIRECCIONAMIENTO DE REGISTRO
Transfiere un byte o palabra desde el registro fuente o localidad en la memoria,
hasta el registro o localidad destino en la memoria. Es fácil comprender el
direccionamiento por registro una vez que se aprende los numerosos registros
que hay en los 8086-080486. Los 8086-80286 contienen los siguiente registros
de 8 bits, utilizando con el direccionamiento por registro AH, AL, BH, BL, CH,
CL, DH, y DL.
También contienen los siguientes registros de 16 bits AX, BX, CX, DX, SP, BP,
SI y DI. En los 80380/80486 los registros, ampliados de 32 bits son EAX, EBX,
ECX, EDX, ESP, EBP, EDI y ESI. Pero no se debe mezclar un registro de 8 bits
con uno de 16 bits, uno de 8 bits con uno de 32 bits, o uno de 16 bits con uno
de 32 bits porque no lo permite el conjunto de instrucciones de 8086-80486. La
tabla presenta algunas versiones de instrucción MOV entre registros. Es
importante mostrar todas las variables por las numerosas combinaciones
posibles.
Lenguaje
ensamblador
Operación
MOV AL, BL
Copia BL en AL
MOV CH, CL
Carga CL en CH
MOV AX, CX
Carga CX en AX
MOV SP, BP
Carga BP en SP
MOV DS, AX
Carga AX en DS
MOV DI, SI
Carga SI en DS
MOV BX, ES
Carga ES en BX
MOV ECX, EBX
Carga EBX en ECX
MOV ESP, EDX
Carga EDX en ESP
MOV ES, DS
No se permite (segmento a
segmento)
MOV CS, AX
No se permite ( registro de
segmento )
MOV BL, BX
No se permite (tamaño mixtos)
DIRECCIONAMIENTO DE REGISTRO INDIRECTO
Transfiere un byte o palabra entre un registro y una localidad de memoria
direccionada por un registro índice o base. En lugar de referenciar por un rótulo
la dirección del operando fuente, el valor del operando es señalado por una
dirección de desplazamiento almacenada en uno de los registros siguientes: SI,
DI,BX, o en algunas veces en el BP.
La ventaja de la instrucción de modo de registro indirecto es que el campo de
direccionamiento en la instrucción utiliza menos bits para seleccionar un
registro que lo que hubiera requerido para especificar una dirección. El
microprocesador reconoce el direccionamiento indirecto de registros por la
sintaxis de la instrucción. El designador del operando fuente es reconocido por
corchetes.
EJEMPLOS
MOV BP, [DX]
LEA AX, [CS]
LEA DI, [SS]
DIRECCIONAMIENTO DE REGISTRO RELATIVO
En este modo el contenido del controlador del programa se suma a la parte de
dirección de la instrucción para obtener una dirección efectiva.
El direccionamiento relativo por registro es similar al direccionamiento base
más índice y al direccionamiento por desplazamiento. En el direccionamiento
relativo por registro, para direccionar datos en un segmento de memoria se
agrega un desplazamiento al contenido de un registro base índice (BP, BX, DI o
SI).
Ejemplo:
MENSAJE1 DB 'EL LENGUAJE ENSAMBLADOR ES', '#'
MENSAJE2 DB 'RAPIDO Y EFICIENTE´','#'
.
.
LEA BX, MENSAJE1
MOV AL,[BX]+4
La orden LEA carga la dirección de desplazamiento en el registro BX. Al
referencias el cuarto elemento de MENSAJE1 se realiza añadiendo la dirección
base (BX) de MENSAJE1 al desplazamiento, +4 en la cadena. El ensamblador
reconoce los tres métodos siguientes para indicar el direccionamiento relativo
base.
LEA [BX]+4
LEA 4[BX]
LEA [BX+4]
DIRECCIONAMIENTO DE BASE INDEXADO
REGISTRO
Con el direccionamiento base indexado, el operando se localiza en el segmento
seleccionado en un desplazamiento determinado por la suma de los contenidos
del registro base, registro índice y opcionalmente un desplazamiento
Ejemplos:
LEA BX MYDATA
MOV SI,25
MOV AX MYDATA [BX] [SI]
DIRECCIONAMIENTO BASE INDEXADO
Con el direccionamiento base indexado, el direccionamiento se localiza en el
segmento seleccionado en un desplazamiento determinado por la suma de dos
contenidos del registro base, registro índice y, opcionalmente un
desplazamiento.
Ejemplo:
LEA BX MY DATA
MOV SI, 25
MOV AX MYDATA
DIRECCIONAMIENTO INDEXADO DIRECTO
En el direccionamiento indexado directo, la dirección de desplazamiento del
operando se calcula sumando el desplazamiento a un registro índice (SI o DI)
en el segmento seleccionado, frecuentemente, el direccionamiento indexado
directo se utiliza para acceder a los elementos de un ARRAY estático. El valor
del desplazamiento localiza el comienzo del ARRAY el valor almacenado en el
registro índice selecciona uno de modo simple en la estructura. Como los
elementos son del mismo tipo de datos y tamaño, por moverse a través del
ARRAY basta en incrementar o decrementar sistemáticamente en el
desplazamiento.
Ejemplo:
MOV SI, 4
MOV AL, ARRAY 1 [SI]
LEA BX MYDATA
MOV 51,25
MOV AX MYDATA [BX] [SI]
Internamente el microprocesador tiene 7 registros rotulados A(para el
acumulador );B, C, D, E, F H y L estos registros tiene 8 bits de ancho y puede
acomodar un bvte . el código de operación de una instrucción leída de la
memoria durante el ciclo de fetch es transferido al registro de instrucción. Es
entonces decodificada por el control para determinar la secuencia de microoperaciones necesarias ejecutar la instrucción.
1.3 Interrupciones.
Una interrupción es una detensión de la ejecución del microprocesador para
dar oportunidad a la maquina de comunicarse con los dispositivos perifericos.
Puede decirse que una interrupción es el elemento más importante para
ejecutar un programa debido a que estas permiten la interacción entre el
usuario y la maquina.
Una interrupción es un mecanismo de control; básicamente ocasiona que la
CPU detenga la ejecución del programa actual transfiera el control a una rutina
de servicio y al termino de esta prosigue con la ejecución del programa
interrumpido a otros mecanismos para transferencia de control tales como las
instrucciones JMPCALL/ RED siempre se encuentran bajo el control del
programa, la familia de las microcomputadoras y compatibles aceptan dos tipos
de interrupciones las del HARDWARE Y SOFTWARE.
EJECUCION DE UNA INTERRUPCION
Para que una interrupción se ejecute correctamente es necesario almacenar el número de
función en el registro acumulador AH (y demas registros de propósito general, si así se
requiere), y posteriormente mandar a llamar el tipo de interrupción requerido.
A continuación se mostrara un fragmento de un programa para ejemplificar
la ejecución de una interrupción.
;CODIGO PARA BORRAR PANTALLA
MOV CX, 0000
MOV DX, 2479H
MOV BH, 07
MOV AH, 06
MOV AL, 00
INT 10H
RET
END
Como puede verse en este ejemplo, para ejecutar la interrupción 10H,
primero fue necesario cargar el valor de la función en el registro acumulador y
los demás atributos en los demás registros de propósito general.
El funcionamiento de una interrupción existe cuando el microprocesador
concluye al ejecutar la instrucción en curso, entonces para determinar si una
interrupción esta activa se comprueba:
1. Alguna instrucción en ejecución
2. Trampa
3. NMI
4. Sobreflujo del segmento del procesador
5. INTR
6. La instrucción INT en el orden citado si está presente una o más de estas condiciones
de interrupciones ocurre lo siguiente:
1.- Se salva el contenido de registro de banderas en pila.
2.- Se desactivan las banderas de interrupciones IF y TF esto deshabilita la terminal INTR
y la característica de trampa,
3.- Se salva el contenido de registro CS de segmentos de código hacia la pila,
4.- Se salva el contenido del apuntador de instrucción IP en la pila,
5.- Se recupera el contenido del vector de la interrupción y se coloca en IP y en CS de
modo que la siguiente instrucción se ejecuta en el procedimiento de servicio de la
interrupción diseccionada por el vector.
TIPOS DE INTERRUPCIONES
Recordemos que las interrupciones internas y externas se
inician a partir de señales que ocurren en la CPU. Y esta se
encuentra lista para atender a la interrupción a quien le
interrumpió, pasa el control ala rutina llamada manejador de
interrupciones, esta rutina define la causa de las
interrupciones, proporciona el servicio solicitado y regresa el
control a la CPU para que esta pueda proseguir a lo que estaba
haciendo.
INTERNAS (DEL PROGRAMA)
Surgen debido a la utilización ilegal o errónea de una instrucción de datos. La
interrupción interna también se llama trampa. Algunos ejemplos de las
interrupciones preocupadas o condiciones de error internas son los sobre flujos
de registro, intentar dividir entre cero un código de operación no valido,
desbordamiento de pila y violación de la Protección. Por lo general estas
condiciones de error ocurren, como resultado de una determinación prematura
de la ejecución de una instrucción. El programa de servicio que procesa la
interrupción interna determina la medida correctiva que se debe tomar.
La diferencia entre las interrupciones internas y externas, es que las internas se
inician por una condición excepcional causada por el programa mismo, mas
bien que por un evento externo. Las interrupciones internas son sincronas con
el programa en tanto que las externas no lo son.
VECTORES PARA INTERRUPCION
NUM.
DIRECCION
MICROPROCESADOR
FUNCION
0
OH – 3H
8086-80486
Error al dividir
1
4H-7H
8086-80486
Paso a paso
2
8H –BH
8086-80486
Nmi Int. Hardware
3
CH-FH
8086-80486
Punto de ruptura
4
10H-13H
8086-80486
Int. Por sobre flujo
5
14H-17H
80286-80486
Int. de BOUND
6
18H-1BH
80286-80486
Código invalido
7
1CH-1FH
80286-80486
Int. De emulación
8
20H-23H
80386 -80486
Doble falta
9
24H-27H
80386- 80486
Desbordamiento de segmento
10
28H-2BH
80386- 80486
Segmento de estado de tarea
11
2CH-2FH
80386- 80486
No hay segmento
12
30H-33H
80386- 80486
Falla de pila
13
34H-37H
80386- 80486
Falla general de protección
14
38H-3BH
80386- 80486
Falla de página
15
3CH-3FH
80386- 80486
Reservado
16
40H-43H
80386- 80486
Error de punto decimal
17
44H-47H
80486SX int
De verificación de alineación
18-31
48H-7FH
8086-80486
Reservado
32-255
80H-3FFH
8086-80486
Int. Por el usuario.
INTERRUPCIONES EXTERNAS
Las interrupciones internas provienen de dispositivos de entrada y salida (E/S).
De un dispositivo de temporizacion, de un circuito que monitorea la fuente de
alimentación de cualquier otra fuente externa. Algunos ejemplos que producen
las interrupciones externas son dispositivos de entrada y salida que terminan la
trasferencia de datos, tiempo transcurrido de un evento o falla de energía.
Puede ocurrir una interrupción por tiempo ilimitado de un programa que este en
un ciclo que no termina y que, por lo tanto excede su tiempo asignado una
interrupción por falla de energía puede tener como su rutina de servicio a un
programa que transfiere el estado completo de la CPU. A una memoria no
volátil en pocos segundos anteriores a una falla de energía.
UTILIZACION DE LAS INTERRUPCIONES DEL BIOS Y DEL MS DOS
Si la pastilla del microprocesador forma el núcleo de la computadora
ciertamente la rutina del BIOS Y del DOS son los cerebros de la máquina cada
computadora esta programada con una cierta cantidad de información antes de
dejar la factoría, esta información esta almacenada en el HARDWARE
ROM(memoria sólo de lectura).
Típicamente la mayoría de las rutinas del BIOS ( sistema básico de entrada y
salida), esta almacenada en ROM y es permanente.
EL DOS. Sistema Operativo de discos puede ser considerado como una
memoria, añadida en una fecha posterior, realmente es memoria que se añade
cada vez que la computadora se conecta o sé inicializa con el DOS, es
memoria no permanente, memoria que puede ser actualizada y cambiada con
cada nueva liberación del DOS típicamente las operaciones s del DOS son
almacenadas en RAM(memoria de acceso aleatorio o residen en el disco hasta
que se necesiten).
INT 1AH
La interrupcion de BIOS, 1AH, permite leer y escribir la fecha y hora actuales
desde y al reloj del sistema. La tabla siguiente es un listado de las opciones
disponibles con la interrupción del BIOS tipo 1AH.
INTERRUPCION 1AH
Valor AH
Función
AH=0
Lee inicializacion reloj actual
AH=1
Inicializa reloj actual
AH=2
Lee hora--reloj de tiempo real
AH=3
AH=4
Entrada
Salida
CX--Bytes superiores del reloj
DX--Bytes inferiores del reloj
AL--0,si temporizador no ha pasado 24 horas
CX=
DX=
Bytes superiores del reloj
Bytes inferiores del reloj
CH--BCD horas
CL--BCD minutos
DH--BCD segundos
Inicializa hora--reloj de tiempo real
CH=
CL=
DH=
DL=
BCD horas
BCD minutos
BCD segundos
1--hora del diaundos
0--hora estandar
CH--BCD siglo
CL--BCD año
DH--BCD mes
DL--BCD dia
Lee fecha-- reloj de tiempo real.
AH=5
Inicialioza Fecha--reloj de tiempo real
CH=
CL=
DH=
DL=
AH=6
Inicializa alarma (hasta 23:59:59)
CH=
CL=
DH=
AH=7
Reinicializa alarma.
BCD
BCD
BCD
BCD
siglo
año
mes
dia
BCD horas
BCD minutos
BCD segundos
INT 10H
Muchas veces cuando se programa, la entrada o salida de la computadora
necesita ser mostrada en la pantalla del monitor.
Con frecuencia esto
requerirá una simple operación de borrado de pantalla; en otras ocasiones se
podrá desear cambiar los colores o atributos de la pantalla. El control de la
pantalla puede conseguirse fácilmente con las interrupciones del BIOS tipo 10H
. La tabla siguiente es un listado de las posibles variaciones programables
con las interrupciones tipo 10H.
INTERRUPCION 10H
Valor
AH
Función
Salida
Entrada
AL=0
AL=1
AL=2
AL=3
AL=4
40x25 B/W
40x25 COLOR
80x25 B/W
80x25 COLOR
320x200 color gráficas
Control de interfaz del CRT
AH=0
Inicializa el modo de visualizar
AL=5
AL=6
AL=10
322x200 B/W gráficas
640x200 B/W gráficas
640x350E.G.A.Graficas
AH=1
Inicializa tipo de cursor
CH=
CL=
Bits 4-0 principio de línea para el cursor
Bits 4-0 fin de linea para cursor
AH=2
Inicializa posición de cursor
DH=
DL=
BH=
Fila
Columna
Número página de pantalla
Lee posición de cursor (valores hasta
ejecusion)
DH=
DL=
CH=
CL=
BH=
Fila
Columna
Modo cursor
Modo cursor
Número página de pantalla
AH=4
Obtiene posicion lapiz luminoso (valores
hasta ejecusión)
AH=0
AH=1
DH=
DL=
CH=
BX=
Conmutacion no abajo/disparo
Respuestas validas; sigue:
Fila
Columna
Grafo linea (0-199)
Columna Grafica
AH=5
Inicializa página pantalla activa
AL=
Valor nueva página
Modos 0 y 1 (0-7)
Modos 2 y 3 (0-3)
Enrrola página activa hacia arriba
AL=
CH=
CL=
DH=
DL=
BH=
Número de lineas; 0 para pantalla entera
Fila, esquina superior izquierda
Columna, esquina superiorzquierda
Fila,esquina inferior derecha
Columna, esquina inferior derecha
Atributo a ser usado
Enrrola página activa hacia abajo
AL=
CH=
CL=
DH=
DL=
BH=
Número de lineas; 0 para pantalla entera
Fila, esquina superior izquierda
Columna, esquina superior izquierda
Fila,esquina inferior derecha
Columna, esquina inferior derecha
Atributo a ser usado
AH=3
AH=6
AH=7
Manipulacion de caracteres
AH=8
Lee atributo/caracter en posición cursor
BH=
AL=
AH=
Página pantalla
Caracter leido
Atributo de caracter
AH=9
Escribe atributo/caracter en posicion
cursor
BH=
CX=
AL=
BL=
Página pantalla
Cuenta de caracteres a escribir
Caracter a escribir
Atributo de caracter
AH=10
Escribe caracter en posición cursor
BH =
CX =
AL =
Visualiza página
Cuenta de caracteres a escribir
Caracter a escribir
BH =
BL =
Paleta ID (0-127)
Color para paleta ID
0--Fondo (0-15)
1--paleta
0--Verde(1),rojo(2),amarillo(3)
1-- Cyan (1), magenta (2),
Interfaz de gráficos
AH=11
Selecciona paleta colores
AH=12
Dibuja punto en pantalla
DX=
CX=
AL=
Fila (0-199)
Columna (0-319/639)
Color del punto
AH=13
Lee informacion punto
DX=
CX=
AL=
Fila (0-199)
Columna (0-319/639)
Valor del punto
Salida teletipo ASCII
AH=14
Escribe a página activa
AL=
BL=
Caracter a escribir
Color primer plano
AH=15
Devuelto a estado video
AL=
AH=
BH=
Modo actual
Número de columnas de pantalla
Página pantalla actual
AH=16
Reservado
AH=17
Reservado
AH=18
Reservado
ES:BP=
CX=
DX=
BH=
AL=0
Señala a cadena
Longitud de cadena
Posicion de cursor para comienzo
Número de página
BL= atributo(car,car,car...car)
Cursor no transferido
BL= atributo (car,car,car...car)
Cursor es transferido
(car,atr,car...atr)
Curso no
transferido
(car,atr,car...atr)
Cursor es transferido.
AH=19
Escribe cadena
AL=1
AL=2
AL=3
INTERRUPCION DEL DOS ( 21H)
La interrupcion 21H del DOS es una interrupcion de llamada a funcion. Las
especificaciones y requerimientos para utilizar esta interrupcion se muestran en
la siguiente tabla:
INTERRUPCION 21H
Valor
AH
Función
Entrada
Salida
AH = 1
Espera y visualiza caracter de teclado
con comprobación CTRL-BREAK
AH = 2
Visualiza caracter de teclado con
comprobación CTRL-BREAK
AH = 3
Entrada asíncrona de caracter
AH = 4
Salida asíncrona de caracter
DL =
Caracter a enviar
AH = 5
Caracter a escribir
DL =
Caracter a escribir
AH = 6
Entrada caracter de teclado
DL =
0FFH
Caracter introducido
AH = 7
Espera para caracter de teclado (no
visualiza)
AL - Caracter introducido
AH = 8
Espera para caracter de teclado (no
visualiza-comprueba CTRL-BREAK)
AL - Caracter introducido
AH = 9
Visualiza cadena
DS:DX=
Dirección de cadena. Debe finalizar con centinela
$
AH = A
Cadena teclado a buffer
DS:DX=
Dirección de buffer. Primer byte=tamaño,
segundo byte=número de caracteres leidos
AH = B
Status de entrada de teclado
AH = C
Borra buffer teclado y llama función
AL =
1,6,7,8,0A - Número función
AH = D
Unidad implícita disco (reset)
Ninguna
Ninguna
AL - Cacter introducido
DL =
Caracter a visualizar
AL - Caracter introducido
AL-No. caracter=0FFH Caracter = 0
AH = E
Unidad implícita disco (seleccionada)
DL =
AL - Núm. unidades
0 - Unidad A
1 - Unidad B, etc.
AH = 19 Código unidad (ímplicito)
AH = 25 Interrupción (inicializa)
AH=2A
Fecha (lee)
AH=2B
Fecha (inicializa)
AH=2C
Hora (lee)
AH=2D
Hora (inicializa)
AH=2E
Verifica estado(inicializa)
AH=35
Direccion interrupcion (lee)
AL - Núm. unidades
0 - Unidad A
1 - Unidad B, etc.
DS:DX =
Dirección del vector de interrupción
AL=
Número de interrupción
CX--Año(80 a 99)
DH--Mes
DL--Dia(1 a 31)
CX:DX
Igual que antes
AL--0 si valido
OFF si no valido
CH--Horas (0-23)
CL--Minutos(0-59)
CX:DX
DL=
AL=
Igual que antes
AL--0 si valido
OFF--si no valido
0
AL= 0
0;verifica off
1;verifica on
Número de interrupción
ES:BX--apunta a direccion vector
DL=
Unidad (0--implicita,1--A,2--B,etc.)
AX--sectores/apiñamiento(FFFF si invalido)
BX--Número apiñamiento libres
CX--Bytes por sector
DX--Número total de apiñamientos
AH=36
Disco espacio disponible
AH=39
Hace directorio
DS:DX
Dirección de cadena para directorio
AH=3A
Eliminar directorio
DS:DX
Dirección de cadena para directorio
AH=3B
Cambia directorio
DS:DX
Dirección de cadena para nuevo directorio
DS:DX
AH=3C
Archivo (crea)
Dirección de cadena para archivo
AX--Retorno maipula archivo
Atributo archivo
CX=
DS:DX
AL=
Dirección de cadena para archivo
0--Abre para leer
1--Abre para escribir
2--Abre para ambos
AX--Retorno manipula archivo
AH=3D
Archivo (abre)
AH=3E
Manipula archivo(cierra)
BX=
Manipula archivo
Archivo o dispositivo(lee)
BX=
CX=
DS:DX
Manipula archivo
Número de bytes a leer
Direccion de buffer
AX--Número de bytes a leer
AH=40
Archivo o dispositivo(escribe)
BX=
CX=
DS:DX
Manipula archivo
Número de bytes a escribir
Dirección de datos a escribir
AX--Número de bytes a escribir
AH=41
Archivo (suprime)
DS:DX
Dirección de archivos cadena
Archivo (pone atributo)
CX:DX
AL=0
AL=1
AL=2
Desplazamiento en bytes
Puntero desplazado (CX:DX) bytes desde el
comienzo del archivo
Puntero a posición actual más desplazamiento
Puntero a EOF más desplazamiento
DS:DX
Dirección de archivo cadena
AH=3F
AH=42
AH=43
Archivo (Inicializa atributo)
SI AL=0, atributo devuelto a CX
SI AL=1, inicializa archivo con atributo de CX
DL=
Número Unidad (0--implicita,1--unidad A,2-unidad B)
Dirección buffer DS:DI--Devuelve dirección de
cadena
AH=47
Direccion actual
AH=54
Verifica estado
Ninguna
AL--0 si verifica off
1 si verifica on
AH=56
Archivo(renombra)
DS:DX
ES:DI
Dirección de cadena para información antigua
Dirección de cadena para información nueva
DS:DI=
Definición y Tipos de Interrupciones.
La primera cosa de todas, ¿qué son las interrupciones?, bien, las interrupciones son un
"mecanísmo" por medio del cual hacemos que la CPU deje la tarea en la que estaba para que
se vaya a ocupar de otra cosa distinta, es decir, es una forma de llamar la atención de la CPU
de tal forma que cada dispositivo cuando necesita ser atendido por la CPU, emite una
interrupción o señal haciendo que la CPU vaya a atenderla de inmediato. Esto es
importantísimo ya que de no existir interrupciones, la CPU debería de ir preguntando, cada
cierto tiempo, a los dispositivos para ver si necesitan de su intervención y como podeis
suponer, eso significaría lentitud, mucha lentitud.
Por tanto, quedaros con que las interrupciones sirven para controlar el hardware, ya que son
las que llaman a la CPU cuando este, el hardware, necesita la intervención de la misma.
Las interrupciones se pueden dividir en 2 grupos:
1. Interrupciones de Software. También son conocidas como "falsas interrupciones" ya que
se producen como consecuencia de la ejecución de otra instrucción al no ser el hardware las
que las produce. Otra forma de entender estas interrupciones, es verlas desde el punto de vista
de llamadas a subrutinas, lógicamente, la gracia está en que esas subrutinas no son nuestras,
sino que son las propias de cada sistema operativo, driver o similar tiene. Quedaros pues, con
que somos nostros los que hacemos invocamos a la interrupción.
Este tipo de interrupción es el más habitual en la programación.
2. Interrupciones de Hardware. Este tipo de interrupción es invocado directamente por los
dispositivos hardware de nuestro ordenador, por lo que "son bastante más auténticas" que las
anteriores. Al producir algún dispositivo hardware la interrupción el controlador de
interrupciones o PIC se encarga de gestionarla determinando, en el caso de producirse más de
una interrupción a la vez, cual de ellas tiene más prioridad y debe de ser gestionada por la
CPU. El funcionamiento de este tipo de interrupciones es bastante similar y se suele utilizar
mucho para la programación de sistemas de comunicaciones.
La Tabla de Vectores de Interrupciones.
Seguro que alguno se ha preguntado, "si cuando llamamos a una interrupción se ejecuta una
determinada rutina...¿dónde narices se encuentra esta rutina?, es más, ¿cómo sabe nuestra
CPU dónde encontrarla?."
Bien, la respuesta a estas dos preguntas (y muchas más) se encuentra en la tabla de vectores
de interrupción. Dicha tabla es una estructura que se crea durante la inicialización del
ordenador y se coloca, en el principio de nuestra memoria (segmento 0 y desplazamiento 0).
Dicha estrucutura ocupa y de forma justa 1Kb, ya que dispone de 256 entradas de 4 bytes cada
una. Lo importante de todo esto es que, dicha estructura, almacena la dirección, en memoria,
de las distintas rutinas que van ligadas a las distintas interrupciones, de tal modo que cuando
invocamos, mediante interrupción software, o se invoca, mediante hardware, una interrupción,
lo que se hace es utilizar un índice que va ligado a la interrupción, de tal manera que, con dicho
índice, se acude a la tabla de vectores de interrupción para que el sistema encuentre la
dirección de la rutina en dónde se encuentra el verdadero tratamiento a la interrupción, es
decir, si se produce la interrupción x, lo que se hace es acudir a la tabla con el índice x para
encontrar la entrada (recordar que eran 256 entradas con 4 bytes cada una) que contiene la
dirección en memoria de la rutina que sirve para tratar a la interrupción de índice x.
Como cada entrada es de 4 bytes, es fácil adivinar que dichos 4 bytes forman la dirección, ya
que 2 de esos bytes se utilizan como segmento y los otros 2 como desplazamiento, total, que
ya tenemos la dirección de memoria con la rutina que hay que utilizar.
Ahora pensar por un momento que somos nostros los que, conociendo la dirección de memoria
de una de esas rutinas, cambiamos dicha rutina por una nuestra para que al producirse una
determinada interrupción ocurra lo que a nosotros nos interese...Como podéis observar, las
posibilidades son muy interesantes, tan sólo tenéis que mirar el efecto de luz del Visualizator
v:2.0 (ir a sencción de Bájate algo interesante), dicho efecto se consiguió poniendo en la rutina
que se encargaba de controlar la interrupción de reloj del sistema, el código necesario para el
efecto de luz, con lo que al producirse la interrupción de reloj se ejecutaba también el código
del efecto y como la interrupción de reloj se produce contínuamente, los efectos son muy
buenos, vamos, que si queréis hacer ese efecto acudiendo a un bucle While lo llevais claro :-(.
Espero haber despertado, con este artículo, el interés por saber dominar las interrupciones. Si
queréis saber más, tan sólo teneis que buscar información en libros sobre programación de
dispositivos tales como ratón, VGA, etc, en los que se acude siempre a ellas. Ahora mismo
estoy pensando el hacer un artículo sobre como controlar el ratón así que puede que aparezca
en esta actualización de la revista, además, es la mejor forma de entender las interrupciones
¿o no?. ;).
http://usuarios.lycos.es/macedoniamagazine/varios2.htm
1.3.1
Hardware.
Ver archivo: Interrupciones 2005.pft
Las interrupciones del HARDWARE son invocadas asincronamente es decir
pueden ocurrir en cualquier momento que no se encuentran bajo el control del
programa con un dispositivo o evento interno.
Interrupciones internas de hardware
Las interrupciones internas son generadas por ciertos eventos que surgen
durante la ejecución de un programa.
Este tipo de interrupciones son manejadas en su totalidad por el hardware y no
es posible modificarlas.
Un ejemplo claro de este tipo de interrupciones es la que actualiza el contador
del reloj interno de la computadora, el hardware hace el llamado a esta
interrupción varias veces durante un segundo para mantener la hora
actualizada.
Aunque no podemos manejar directamente esta interrupción (no podemos
controlar por software las actualizaciones del reloj), es posible utilizar sus
efectos en la computadora para nuestro beneficio, por ejemplo para crear un
"reloj virtual" actualizado continuamente gracias al contador del reloj interno.
Unicamente debemos escribir un programa que lea el valor actual del contador
y lo traduzca a un formato entendible para el usuario.
Interrupciones externas de hardware
Las interrupciones externas las generan los dispositivos perifericos, como
pueden ser: teclado, impresoras, tarjetas de comunicaciones, etc. También son
generadas por los coprocesadores.
No es posible desactivar a las interrupciones externas.
Estas interrupciones no son enviadas directamente a la UCP, sino que se
mandan a un circuito integrado cuya función es exclusivamente manejar este
tipo de interrupciones. El circuito, llamado PIC 8259A, si es controlado por la
UCP utilizando para tal control una serie de vias de comunicación llamadas
puertos.
http://members.tripod.com/~MoisesRBB/unidad6.htm
1.3.2
Software.
Ver archivo: Interrupciones 2005.pft
Por otro lado las interrupciones del SOFTWARE no interrumpen algo si no son
variantes de las rutinas las cuales pueden invocarse a voluntad y son
controladas por un programa en forma sincrónica o sea, que se conoce con
todo lo relacionado con su ejecución puesto que el programa controla el
momento y la manera en que son llamadas mediante la secuencia de
instrucciones CALL y RET, cuando un programa ejecuta una instrucción CALL
se conoce previamente la dirección de la rutina llamada de tal forma que la
CPU pueda saltar al código, que se encuentra ahí y ejecutarle. En la mayoría
de los casos el programa TLINK.EXE determina y asigna las direcciones de las
rutinas es claro que el enlazador no puede saber de antemano donde se
encuentran las rutinas MS DOS y del BIOS en la memoria de la otra cuando un
programa ejecuta una instrucción INT # de interrupción en la CPU
automáticamente accesa la memoria baja a fin de obtener el desplazamiento
La interrupción INT n, llama al procedimiento de servicio de instrucción que
comienza en la dirección representada en el vector número n.
La interrupción IRET es una instrucción especial para retorno y se utiliza
para retornar de las instrucciones del Software y Hardware.
Interrupciones de software
Las interrupciones de software pueden ser activadas directamente por el
ensamblador invocando al número de interrupción deseada con la instrucción
INT.
El uso de las interrupciones nos ayuda en la creación de programas,
utilizandolas nuestros programas son más cortos, es más fácil entenderlos y
usualmente tienen un mejor desempeño debido en gran parte a su menor
tamaño.
Este tipo de interrupciones podemos separarlas en dos categorias: las
interrupciones del sistema operativo DOS y las interrupciones del BIOS.
La diferencia entre ambas es que las interrupciones del sistema operativo son
más fáciles de usar pero también son más lentas ya que estas interrupciones
hacen uso del BIOS para lograr su cometido, en cambio las interrupciones del
BIOS son mucho más rápidas pero tienen la desventaja que, como son parte
del hardware son muy específicas y pueden variar dependiendo incluso de la
marca del fabricante del circuito.
La elección del tipo de interrupción a utilizar dependerá unicamente de las
caracteristicas que le quiera dar a su programa: velocidad (utilizando las del
BIOS) o portabilidad (utilizando las del DOS).
Interrupción 21H
Propósito: Llamar a diversas funciones del DOS.
Sintaxis:
Int 21H
Nota: Cuando trabajamos en MASM es necesario especificar que el valor que
estamos utilizando es hexadecimal.
Esta interrupción tiene varias funciones, para accesar a cada una de ellas es
necesario que el el registro AH se encuentre el número de función que se
requiera al momento de llamar a la interrupción.
Funciones para desplegar información al video.
02H Exhibe salida
09H Impresión de cadena (video)
40H Escritura en dispositivo/Archivo
Funciones para leer información del teclado.
01H Entrada desde teclado
0AH Entrada desde teclado usando buffer
3FH Lectura desde dispositivo/archivo
Funciones para trabajar con archivos.
En esta sección unicamente se expone la tarea específica de cada
función, para una referencia acerca de los conceptos empleados
refierase a la unidad 7, titulada: "Introducción al manejo de archivos".
Método FCB
0FH Abrir archivo
14H Lectura secuencial
15H Escritura secuencial
16H Crear archivo
21H Lectura aleatoria
22H Escritura aleatoria
Handles
3CH Crear archivo
3DH Abrir archivo
3EH Cierra manejador de archivo
3FH Lectura desde archivo/dispositivo
40H Escritura en archivo/dispositivo
42H Mover apuntador de lectura/escritura en archivo
Función 02H
Uso:
Despliega un caracter a la pantalla.
Registros de llamada:
AH = 02H
DL = Valor del caracter a desplegar.
Registros de retorno:
Ninguno
Esta función nos despliega el caracter cuyo codigo hexagesimal
corresponde al valor almacenado en el registro DL, no se modifica ningún
registro al utilizar este comando.
Es recomendado el uso de la función 40H de la misma interrupción en
lugar de esta función.
Función 09H
Uso:
Despliega una cadena de carateres en la pantalla.
Registros de llamada:
AH = 09H
DS:DX = Dirección de inicio de una cadena de caracteres
Registros de retorno:
Ninguno.
Esta función despliega los caracteres, uno a uno, desde la dirección
indicada en el registro DS:DX hasta encontrar un caracter $, que es
interpretado como el final de la cadena.
Se recomienda utilizar la función 40H en lugar de esta función.
Función 40H
Uso:
Escribir a un dispositivo o a un archivo.
Registros de llamada:
AH = 40H
BX = Vía de comunicación
CX = Cantidad de bytes a escribir
DS:DX = Dirección del inicio de los datos a escribir
Registros de retorno:
CF = 0 si no hubo error
AX = Número de bytes escritos
CF = 1 si hubo error
AX = Código de error
El uso de esta función para desplegar información en pantalla se realiza
dandole al registro BX el valor de 1 que es el valor preasignado al video
por el sistema operativo MS-DOS.
Función 01H
Uso:
Leer un caracter del teclado y desplegarlo.
Registros de llamada:
AH = 01H
Registros de retorno:
AL = Caracter leído
Con esta función es muy sencillo leer un caracter del teclado, el código
hexadecimal del caracter leído se guarda en el registro AL. En caso de que
sea un caracter extendido el registro AL contendra el valor de 0 y será
necesario llamar de nuevo a la función para obtener el código de este
caracter.
Función 0AH
Uso:
Leer caracteres del teclado y almacenarlos en un buffer.
Registros de llamada:
AH = 0AH
DS:DX = Dirección del área de almacenamiento
BYTE 0 = Cantidad de bytes en el área
BYTE 1 = Cantidad de bytes leídos
desde BYTE 2 hasta BYTE 0 + 2 = caracteres leídos
Registros de retorno:
Ninguno
Los caracteres son leídos y almacenados en un espacio predefinido de
memoria. La estructura de este espacio le indica que en el primer byte del
mismo se indican cuantos caracteres serán leídos. En el segundo byte se
almacena el número de caracteres que ya se leyeron, y del tercer byte en
adelante se escriben los caracteres leídos.
Cuando se han almacenado todos los caracteres indicados menos uno la
bocina suena y cualquier caracter adicional es ignorado. Para terminar la
captura de la cadena es necesario darle [ENTER].
Función 3FH
Uso:
Leer información de un dispositivo o archivo.
Registros de llamada:
AH = 3FH
BX = Número asignado al dispositivo
CX = Número de bytes a procesar
DS:DX = Dirección del área de almacenamiento
Registros de retorno:
CF = 0 si no hay error y AX = número de bytes leidos.
CF = 1 si hay error y AX contendra el código del error.
Función 0FH
Uso:
Abrir archivo FCB
Registros de llamada:
AH = 0FH
DS:DX = Apuntador a un FCB
Registros de retorno:
AL = 00H si no hubo problema, de lo contrario regresa 0FFH
Función 14H
Uso:
Leer secuencialmente un archivo FCB.
Registros de llamada:
AH = 14H
DS:DX = Apuntador a un FCB ya abierto.
Registros de retorno:
AL = 0 si no hubo errores, de lo contrario se regresara el código
correspondiente de error: 1 error al final del archivo, 2 error en la estructura
del FCB y 3 error de lectura parcial.
Esta función lo que hace es que lee el siguiente bloque de información a
partir de la dirección dada por DS:DX, y actualiza este registro.
Función 15H
Uso:
Escribir secuencialmente a un archivo FCB
Registros de llamada:
AH = 15H
DS:DX = Apuntador a un FCB ya abierto
Registros de retorno:
AL = 00H si no hubo errores, de lo contrario contendra el código del error:
1 disco lleno o archivo de solo lectura, 2 error en la formación o
especificación del FCB.
La función 15H después de escribir el registro al bloque actual actualiza el
FCB.
Función 16H
Uso:
Crear un archivo FCB.
Registros de llamada:
AH = 16H
DS:DX = Apuntador a un FCB ya abierto.
Registros de retorno:
AL = 00H si no hubo errores, de lo contrario contendra el valor 0FFH
Se basa en la información proveida en un FCB para crear un archivo en el
disco.
Función 21H
Uso:
Leer en forma aleatoria un archivo FCB.
Registros de llamada:
AH = 21H
DS:DX = Apuntador a un FCB ya abierto.
Registros de retorno:
A = 00H si no hubo error, de lo contrario AH contendra el código del error:
1 si es fin de archivo, 2 si existe error de especificación de FCB y 3 si se
leyó un registro parcial o el apuntador del archivo se encuentra al final del
mismo.
Esta función lee el registro especificado por los campos del bloque actual y
registro actual de un FCB abierto y coloca la información en el DTA (área
de transferencia de disco o Disk Transfer Area).
Función 22H
Uso:
Escribir en forma aleatoria en un archivo FCB.
Registros de llamada:
AH = 22H
DS:DX = Apuntador a un FCB abierto.
Registros de retorno:
AL = 00H si no hubo error, de lo contrario contendrá el código del error: 1
si el disco está lleno o es archivo de solo lectura y 2 si hay error en la
especificación de FCB.
Escribe el registro especificado por los campos del bloque actual y registro
actual de un FCB abierto. Escribe dicha información a partir del contenido
del DTA (área de transferencia de disco).
Función 3CH
Uso:
Crear un archivo si no existe o dejarlo en longitud 0 si existe. (Handle)
Registros de llamada:
AH = 3CH
CH = Atributo de archivo
DS:DX = Apuntador a una especificaión ASCIIZ
Registros de retorno:
CF = 0 y AX el número asignado al handle si no hay error, en caso de
haberlo CF será 1 y AX contendra el código de error: 3 ruta no encontrada,
4 no hay handles disponibles para asignar y 5 acceso negado.
Esta función sustituye a la 16H. El nombre del archivo es especificado en
una cadena ASCIIZ, la cual tiene como característica la de ser una cadena
de bytes convencional terminada con un caracter 0.
El archivo creado contendra los atributos definidos en el registro CX en la
siguiente forma:
Valor Atributos
00H Normal
02H Escondido
04H Sistema
06H Escondido y de sistema
El archivo se crea con los permisos de lectura y escritura. No es posible
crear directorios utilizando esta función.
Función 3DH
Uso:
Abre un archivo y regrese un handle
Registros de llamada:
AH = 3DH
AL = modo de acceso
DS:DX = Apuntador a una especificación ASCIIZ
Registros de retorno:
CF = 0 y AX = número de handle si no hay errores, de lo contrario CF = 1
y AX = código de error: 01H si no es válida la función, 02H si no se
encontró el archivo, 03H si no se encontr´o la ruta, 04H si no hay handles
disponibles, 05H en caso de acceso negado, y 0CH si el código de acceso
no es válido.
El handle regresado es de 16 bits.
El código de acceso se especifica en la siguiente forma:
BITS
7654321
. . . . 0 0 0 Solo lectura
. . . . 0 0 1 Solo escritura
. . . . 0 1 0 Lectura/Escritura
. . . X . . . RESERVADO
Función 3EH
Uso:
Cerrar archivo (Handle).
Registros de llamada:
AH = 3EH
BX = Handle asignado
Registros de retorno:
CF = 0 si no hubo errores, en caso contrario CF será 1 y AX contendrá el
código de error: 06H si el handle es inválido.
Esta función actualiza el archivo y libera o deja disponible el handle que
estaba utilizando.
Función 3FH
Uso:
Leer de un archivo abierto una cantdad definida de bytes y los almacena en
un buffer específico.
Registros de llamada:
AH = 3FH
BX = Handle asignado
CX = Cantidad de bytes a leer
DS:DX = Apuntador a un área de trabajo.
Registros de retorno:
CF = 0 y AX = número de bytes leidos si no hubo error, en caso contrario
CF = 1 y AX = código de error: 05H si acceso negado y 06H si no es válido
el handle.
Función 40H
Uso:
Escribe a un archivo ya abierto una cierta cantidad de bytes a partir del
buffer designado.
Registros de llamada:
AH = 40H
BX = Handle asignado
CX = Cantidad de bytes a escribir.
DS:DX = Apuntador al buffer de datos.
Registros de retorno:
CF = 0 y AX = número de bytes escritos si no hay errores, en caso de
existir CF = 1 y AX = código del error: 05H si el acceso es negado y 06H si
el handle es inválido.
Función 42H
Uso:
Mover apuntador al archivo (Handle)
Registros de llamada:
AH = 42H
AL = método utilizado
BX = Handle asignado
CX = La parte más significativa del offset
DX = La parte menos significativa del offset
Registros de retorno:
CF = 0 y DX:AX = la nueva posición del apuntador. En caso de error CF
será 1 y AX = código de error: 01H si la función no es válida y 06H si el
handle no es válido.
El método utilizado se configura como sigue:
Valor de AL Método
00H A partir del principio del archivo
01H A partir de la posición actual
02H A partir del final del archivo
Interrupción 10H
Propósito: Llamar a diversas funciones de video del BIOS.
Sintaxis:
Int 10H
Esta interrupción tiene diversas funciones, todas ellas nos sirven para
controlar la entrada y salida de video, la forma de acceso a cada una de las
opciones es por medio del registro AH.
En este tutorial unicamente veremos algunas de las funciones de esta
interrupción.
Funciones comunes de la interrupción 10H.
02H Selección de posición del cursor
09H Escribe atributo y caracter en el cursor
0AH Escribe caracter en la posición del cursor
0EH Escritura de caracteres en modo alfanumérico
Función 02H
Uso:
Posiciona el cursor en la pantalla dentro de las coordenadas válidas de
texto.
Registros de llamada:
AH = 02H
BH = Página de video en la que se posicionará el cursor.
DH = Fila
DL = Columna
Registros de retorno:
Ninguno.
Las posiciones de localización del cursor son definidas por coordenadas
iniciando en 0,0, que corresponde a la esquina superior izquierda hasta
79,24 correspondientes a la esquina inferior derecha. Tenemos entonces
que los valores que pueden tomar los registros DH y DL en modo de texto
de 80 x 25 son de 0 hasta 24 y de 0 hasta 79 respectivamente.
Función 09H
Uso:
Desplegar un caracter un determinado número de veces con un atributo
definido empezando en la posición actual del cursor.
Registros de llamada:
AH = 09H
AL = Caracter a desplegar
BH = Página de video en donde se desplegará
BL = Atributo a usar
Número de repeticiones.
Registros de retorno:
Ninguno
Esta función despliega un caracter el número de veces especificado en CX
pero sin cambiar la posición del cursor en la pantalla.
Función 0AH
Uso:
Desplegar un caracter en la posición actual del cursor.
Registros de llamada:
AH = 0AH
AL = Caracter a desplegar
BH = Página en donde desplegar
BL = Color a usar (sólo en gráficos).
CX = Número de repeticiones
Registros de retorno:
Ninguno.
La única diferencia entre esta función y la anterior es que ésta no permite
modificar los atributos, simplemente usa los atributos actuales.
Tampoco se altera la posición del cursor con esta función.
Función 0EH
Uso:
Deplegar un caracter en la pantalla actualizando la posición del cursor.
Registros de llamada:
AH = 0EH
AL = Caracter a desplegar
BH = Página donde se desplegara el caracter
BL = Color a usar (solo en gráficos)
Registros de retorno:
Ninguno
Interrupción 16H
Propósito: Manejar la entrada/salida del teclado.
Sintaxis:
Int 16H
Veremos dos opciones de la interrupción 16H, estas opciones, al igual que
las de otras interrupciones, son llamadas utilizando el registro AH.
Funciones de la interrupción 16H
00H Lee un caracter de teclado
01H Lee estado del teclado
Función 00H
Uso:
Leer un caracter del teclado.
Registros de llamada:
AH = 00H
Registros de retorno:
AH = código de barrido (scan code) del teclado
AL = Valor ASCII del caracter.
Cuando se utiliza esta interrupción se detiene la ejecución del programa
hasta que se introduzca un caracter desde el teclado, si la tecla presionada
es un caracter ASCII su valor será guardado en el registro AH, de lo
contrario el código de barrido será guardado en AL y AH contendrá el
valor 00H.
El código de barrido fué creado para manejar las teclas que no tienen una
representación ASCII como [ALT], [CONTROL], las teclas de función,
etc.
Función 01H
Uso:
Leer estado del teclado.
Registros de llamada:
AH = 01H
Registros de retorno:
Si la bandera de cero, ZF, está apagada significa que hay información en el
buffer, si se encuentra prendida es que no hay teclas pendientes.
En caso de existir información el registro AH contendrá el código de
la tecla guardada en el buffer.
Interrupción 17H
Propósito: Manejar la entrada/salida de la impresora.
Sintaxis:
Int 17H
Esta interrupción es utilizada para escribir caracteres a la impresora,
inicializarla y leer su estado.
Funciones de la interrupción 16H
00H Imprime un caracter ASCII
01H Inicializa la impresora
02H Proporciona el estado de la impresora
Función 00H
Uso:
Escribir un caracter a la impresora.
Registros de llamada:
AH = 00H
AL = Caracter a imprimir
DX = Puerto a utilizar
Registros de retorno:
AH = Estado de la impresora.
El puerto a utilizar, definido en DX, se especifica así: LPT1 = 0, LPT2 = 1,
LPT3 = 2 ...
El estado de la impresora se codifica bit por bit como sigue:
BIT 1/0 SIGNIFICADO
---------------------------------------0 1 Se agotó el tiempo de espera
123 1 Error de entrada/salida
4 1 Impresora seleccionada
5 1 Papel agotado
6 1 Reconocimiento de comunicación
7 1 La impresora se encuentra libre
Los bits 1 y 2 no son relevantes.
La mayoria de los BIOS unicamente soportan 3 puertos paralelos aunque
existen algunos que soportan 4.
Función 01H
Uso:
Inicializar un puerto de impresión.
Registros de llamada:
AH = 01H
DX = Puerto a utilizar
Registros de retorno:
AH = Status de la impresora
El puerto a utilizar, definido en DX, se especifica así: LPT1 = 0, LPT2 = 1,
etc.
El estado de la impresora se codifica bit por bit como sigue:
BIT 1/0 SIGNIFICADO
---------------------------------------0 1 Se agotó el tiempo de espera
123 1 Error de entrada/salida
4 1 Impresora seleccionada
5 1 Papel agotado
6 1 Reconocimiento de comunicación
7 1 La impresora se encuentra libre
Los bits 1 y 2 no son relevantes.
La mayoria de los BIOS unicamente soportan 3 puertos paralelos aunque
existen algunos que soportan 4.
Función 02H
Uso:
Obtener el estado de la impresora.
Registros de llamada:
AH = 01H
DX = Puerto a utilizar
Registros de retorno:
AH = Status de la impresora.
El puerto a utilizar, definido en DX, se especifica así: LPT1 = 0, LPT2 = 1,
etc.
El estado de la impresora se codifica bit por bit como sigue:
BIT 1/0 SIGNIFICADO
---------------------------------------0 1 Se agotó el tiempo de espera
123 1 Error de entrada/salida
4 1 Impresora seleccionada
5 1 Papel agotado
6 1 Reconocimiento de comunicación
7 1 La impresora se encuentra libre
Los bits 1 y 2 no son relevantes.
La mayoria de los BIOS unicamente soportan 3 puertos paralelos aunque
existen algunos que soportan 4.
Introducción
Todo el semestre hemos usado interrupciones para hacer llamado a servicios de DOS y
BIOS; hasta ahora, principalmente las hemos visto como formas de llamar al sistema
operativo.
La razón por la que este sistema es llamado "interrupción" es precisamente porque
funcionan interrumpiendo la ejecución del programa en un punto dado, ejecutan una
labor determinada y regresan a donde estaban. Es como estar trabajando en la tarea,
recibir una llamada telefónica, atenderla y al terminar lograr regresar exactamente al
estado previo para continuar con la tarea
Existen dos tipos de interrupciones:


Interrupciones de hardware: son las más primitivas y origen del concepto. Están
diseñadas para que el procesador pueda atender a los dispositivos aún a mitad de
la ejecución de un programa que no está detectándolos.
Interrupciones de software: permiten al software emular las operaciones que se
hacen al atender el hardware. También permiten contener una interfase universal
a los servicios del sistema operativo, que son independientes de las versiones del
sistema operativo.
Cuando un dispositivo requiere atención del CPU, le avisa por medio de una señal
(electrónica) que llamamos "Interrupción". Esta señal físicamente llega a un pin del
CPU; cuando esto ocurre, el CPU termina la instrucción que estaba ejecutando, salva en
la pila la dirección actual (CS, IP) para poder continuar más adelante en el punto donde
se quedó, y salta a ejecutar el código de atención de la interrupción, que generalmente
es parte del sistema operativo. Dado que el código que atiende la interrupción puede
encontrarse en distintos lugares de memoria, se requiere algún mecanismo para que el
CPU encuentre eficientemente donde continuar la atención de la interrupción. Este
mecanismo es conocido como "tabla de interrupciones", y se basa en reconocer por un
código a cada interrupción, el cual será usado para la búsqueda en esta tabla. Esta tabla
de interrupciones la encuentra el 80x86 al inicio de la memoria, en el primer 1 Kb. Está
formada por un arreglo de 256 direcciones, cada una de 32 bits, pues contiene al
segmento y al desplazamiento (en orden inverso, como es costumbre en Intel). De modo
que si se recibe el código de interrupción 0, se consulta la información en la localidad
0:0, y de ahí se obtienen el segmento y el desplazamiento correspondientes. Si se recibe
el código de interrupción 8, se consulta la información en la localidad 0:20h (20h = 32 =
8 por 4, dado que cada entrada en el arreglo tiene 4 bytes), y de ahí se ejecuta el código
correspondiente. Al terminar el código de atención de la interrupción, ejecuta una
instrucción IRET, que regresa el punto de ejecución a donde se había quedado,
Funcionan de un modo similar a las de hardware, solamente que en vez de que un
dispositivo envíe la señal, lo hace el programa utilizando la instrucción INT. Esta
instrucción causa que se ejecute todo el proceso anterior, pero señalada por un
programa.
Programas residentes / programas transientes
La mayor parte de los programas con los que hemos trabajado son programas
"transientes", es decir, se cargan en memoria, se ejecutan y al terminar su ejecución,
regresan el control al sistema operativo y se eliminan de memoria.
Un programa residente (Terminate and Stay Resident, de ahí las siglas TSR
comúnmente usadas) consiste en que un programa se carga en memoria, se ejecuta,
prepara la ejecución de la segunda sección (por medio de un control fino sobre las
interrupciones), y libera solamente la memoria del código de preparación. De este
modo, una sección de su código queda "latente", en espera de ser disparado por un
evento: generalmente, una interrupción.
Entre las aplicaciones de los programas residentes tenemos:



El sistema operativo DOS: queda en memoria esperando a que otro programa lo
llame, para entonces ejecutar un determinado código.
Programas que esperen una combinación de teclas, para entonces realizar su
acción. Por ejemplo, sacar un menú con acciones específicas.
Programas que sustituyan la funcionalidad del sistema operativo. Por ejemplo,
las versiones 2 a 3 de Novell Netware se cargaban después de DOS, y le
anexaban la capacidad de acceder a unidades de red.
Programación de TSRs
Para programar un TSR, utilizaremos una serie de servicios de interrupciones que nos
facilitan la capacidad de dejar una sección del programa activa, así como cambiar la
dirección a la que apunta una interrupción. Resumiendo, tendremos dos grandes
secciones en un programa residente:


La sección transiente, que lleva a cabo la inicialización requerida y prepara los
vectores de interrupción (las direcciones que están en la tabla), de modo que
apunten a los procedimientos del programa residente que van a atenderlas.
La sección residente, la cual contiene los procedimientos de atención a las
interrupciones. Terminar un programa y dejar una sección residente en memoria.
Cuando llamamos al servicio 4Ch de la INT 21h, toda la memoria que ocupó nuestro
programa se marca como libre y el sistema operativo puede reutilizarla. Esto sería
desastroso en el caso de un programa residente, pues el código que atiende
interrupciones podría sobreescribirse, con resultados impredecibles. Por ello, se debe
terminar el programa de modo que deje ocupada su memoria. Para ello, existen varias
opciones:

La interrupción 27h, que termina el programa y deja residente en memoria la
zona indicada por DS:DX, donde DS apunta al segmento donde se encuentra el

código, y DX al desplazamiento final del código que debe respetarse. De este
modo, no se liberará memoria indebidamente.
Servicios de la 21h, que no veremos en este curso.
Interceptar una interrupción
Para que se ejecute un procedimiento que nosotros desarrollamos, en atención de una
interrupción, es común usar la técnica de "interceptar", que consiste en guardar el vector
anterior de interrupción, cambiarlo para que apunte a nuestro programa residente, y al
final de nuestra rutina residente, llamar al vector anterior. Esto conserva la
funcionalidad regular, y al mismo tiempo nos permite realizar actividades adicionales.
Cabe aclarar algunas de las interrupciones importantes que no hemos comentado por no
ser tan usadas en software:



INT 08h - es llamada por el reloj del sistema, 18.2 veces por segundo, y entre
otras cosas lleva el tiempo de BIOS. Podemos interceptarla (no sustituirla) para
que nuestro programa realice algún proceso periódicamente.
INT 09h - es llamada por el teclado, cada vez que se recibe una tecla.
INT 0Ch - de software, es llamada por la interrupción del reloj.
Obviamente hay muchas otras, sirvan estas como ejemplo.
Se pueden interceptar las interrupciones generadas por puertos seriales, paralelos,
división entre 0, una instrucción inválida, etcétera.
Sustituir una interrupción
En ocasiones queremos reemplazar completamente el funcionamiento de una
interrupción; en tal caso, sustituiremos el vector de interrupción para que apunte a
nuestro código, y deberemos terminar la ejecución de nuestro procedimiento con un
IRET, que permitirá regresar al punto donde se ejecutó nuestra interrupción. Por otro
lado, es conveniente asegurarnos de conservar el valor de los registros (generalmente
utilizando la pila) que modifiquemos, de este modo la interrupción no afecta la
ejecución de otros procesos. Acciones válidas dentro de una interrupción En una
interrupción podemos utilizar otros servicios, principalmente de acceso directo al
hardware. Sin embargo, como DOS es un sistema operativo que no fue diseñado para
ser multitarea, diversas funciones no soportan la capacidad de ser reentrantes; esto es,
no pueden ser llamadas otra vez si están a medio ejecutarse. Pero como una interrupción
puede ocurrir en cualquier momento, puede incluso ocurrir cuando está una función a
medio ejecutarse. Por tanto, esto causaría inestabilidad del sistema. Existen dos métodos
para evitar esta inestabilidad:


No usar interrupciones, que es bastante común y apropiado pues también tiene
grandes beneficios de desempeño; cuando un programa residente no requiere
hacer funciones complejas que estén implementadas en el sistema operativo,
sino funciones simples tales como pintar en pantalla, pueden codificarse estas
funciones con acceso directo al hardware y de este modo se evita el problema.
Revisar si está una función del sistema en ejecución, para no volver a llamarla a
mitad de la ejecución. Esto en DOS se hace por medio de un método que durante
mucho tiempo no estaba documentado: la bandera InDOS. Para obtenerla, se
llama al servicio 34h de la interrupción 21h, y nos deja en ES:BX la dirección de
un byte que es esta bandera InDOS. El funcionamiento de la bandera es sencillo:
si está en 0, no estamos a media función de DOS, por lo tanto, podemos sin
problemas ejecutar una función DOS. De lo contrario, si el valor es 1 o superior,
no debemos ejecutar la función DOS en este momento y nuestro programa TSR
deberá posponer el uso de esta función, por lo que probablemente deberemos
manejar la interrupción del reloj para intentar después de un tiempo.
Existen algunas precauciones adicionales que tomar en TSRs, sin embargo, como no
siempre son requeridas, se hace la referencia al PC Interno y otros libros de la
bibliografía.
http://www.sinergia-web.com.mx/clases/asm9708/Temas/clase26.htm
Ejemplos
1. Programa residente muy simple
; RESIDE.ASM: Pequeño programa residente
; Se ejecuta, y cuando se presiona Ctrl + N invierte los colores de
fondo y frente
; en toda la pantalla, usando la memoria de video para modificar el
atributo.
;
PushA Macro
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
EndM
POPA Macro
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
EndM
; Buffer del teclado de BIOS
BiosData Segment AT 40h
ORG 1Ah
Head
DW ?
Tail
DW ?
Buffer
DW 16 DUP (?)
Buffer_End Label Word
BiosData EndS
; Segmento de código
Code Segment
Assume CS:Code
Assume DS:Code
Assume SS:Code
Assume ES:Code
ORG 100h
Start:
JMP
Inicio
; Variables
OldInt Label Word
DirAnt
DD
BanderaLleno
?
DB 0
; Rutina de atención de Interrupción
ParteRes Proc Near
Assume CS:Code,DS:Code
PushA
PushF
CALL CS:DirAnt
rutina que
; IMPORTANTE: Es una llamada FAR a la
; anteriormente atendía al teclado; es
necesaria,
; pues esa rutina se encarga de manejar
el buffer
; de teclado y yo lo voy a usar. Otros
programas
; posiblemente en vez de CALL hagan un
; JMP FAR [CS:DirAnt]
; DESPUÉS de realizar su función
ASSUME DS:BiosData
MOV
BX,BiosData
MOV
DS,BX
MOV
BX,Tail
CMP
BX,Head
JE
Fin
CALL ChecaTecla
CMP
AX,310Eh ; ^N
JNE
Fin
MOV
Tail,BX
; Invertir color de pantalla
MOV
CX,2000
MOV
AX,0B800h
MOV
ES,AX
MOV
DI,0
Ciclo:
MOV
AX,ES:[DI]
XOR
AH,07Fh ; Invierte atributo, todos los bits
correspondientes a colores
MOV
ES:[DI],AX
INC
DI
INC
DI
LOOP Ciclo
Fin:PopA
IRET
ParteRes EndP
ChecaTecla Proc Near
MOV
DX,Tail
SUB
DX,2
CMP
DX,OFFSET Buffer
JAE
OK
MOV
DX,OFFSET Buffer_End
SUB
DX,2
OK: MOV
BX,DX
MOV
AX,[BX]
RET
ChecaTecla EndP
Inicio:
PUSH
PUSH
POP
CLI
PUSH
XOR
MOV
MOV
(reloj)
LEA
MOV
MOV
MOV
MOV
MOV
MOV
POP
STI
LEA
INT
RET
Fin2:
Code EndS
END Start
DS
CS
DS
ES
AX,AX
ES,AX
DI,36 ; 9*4 ; Pues estamos interceptando la interrupción 9
BX,ParteRes
AX,ES:[DI]
OldInt,AX
ES:[DI],BX
AX,ES:[DI+2]
OldInt+2,AX
ES:[DI+2],DS
ES
DX,Fin2
27h
http://www.sinergiaweb.com.mx/clases/asm9708/programa/reside.asm
1. Programa de reloj residente
; Programa de reloj residente
; Bruno Guardia Robles.
.MODEL TINY ; .COM
; Se ensambla con TASM RELOJRES
;
TLINK RELOJRES /t = COM (ver TLINK para ayuda)
.CODE
PushA Macro
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
EndM
POPA
Start:
Macro
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
EndM
ORG
100h
JMP Inicializa
; Variables
Horas
DB
Minutos DB
Segundos DB
PMFlag
DB
DivHi
DW
DivLo
DW
ResultHi DW
ResultLo DW
Actual
DB
Divisor DB
Contador DB
?
?
?
0
0
0
0
0
0
0
0
LeeReloj Proc Near
; Regresa en DX:AX el valor actual del reloj contador interno
de BIOS.
PUSH ES
MOV
AX,40h
MOV
ES,AX
MOV
DI,6Ch
MOV
AX,ES:[DI]
PUSH AX
ADD
DI,2
MOV
AX,ES:[DI]
POP
DX
POP
ES
RET
LeeReloj EndP
DobleDiv Proc Near
; Hace una división de Doble Palabra entre Byte dejando Doble
Palabra
; Rutina para estar orgulloso, fue latosa y está basada en
corrimientos, tal
; como se divide binario a mano.
XOR AX,AX
MOV Actual,AL
MOV ResultLo,AX
MOV ResultHi,AX
MOV CX,33 ; 32 ciclos
Ciclo:
MOV AL,Actual
CMP AL,Divisor
PUSHF
JB
NoCarry
STC ; Encender el Carry si es mayor o igual
JMP SHORT Rotar
NoCarry: CLC ; Apagar el Carry
Rotar:
RCL ResultLo,1
RCL ResultHi,1
POPF
JB
ContCiclos
; Si Actual es menor al Divisor, restar Divisor al Actual
SUB AL,Divisor
MOV Actual,AL
ContCiclos:
; Rotar el dividendo
ROL DivLo,1
RCL DivHi,1
; El bit m s significativo entra a Actual
RCL Actual,1
LOOP Ciclo
; En Actual qued¢ el residuo
RET
DobleDiv EndP
; Calcular la hora en base al valor del contador de reloj de BIOS
Calcula2 Proc Near
; Primero multiplicar DX:AX por 5
XCHG AX,DX
PUSH DX
PUSH AX
PUSH DX
PUSH AX
ROL
AX,1
RCL
DX,1
ROL
AX,1
RCL
DX,1
POP
BX
POP
CX
ADD
AX,BX
ADC
DX,CX
; Ahora, dividir DX:AX entre 91
MOV
DivHi,DX
MOV
DivLo,AX
MOV
Divisor,91
CALL DobleDiv
; Calcular el factor de correcci¢n como Ciclos/50269
; Aproximadamente cada 50000 ciclos se adelanta un segundo
; Las pruebas que hice dan resultados entre 50200 y 50300
; Como factor promedio usar‚ 50260
; Con esto el error se reduce a 1 segundo, 1 segundo y medio
; El factor es m s exacto por la noche, mientras que el
; c lculo de Ciclos*5/91 es m s exacto temprano, lo que los
; equilibra bastante.
POP
AX
POP
DX
MOV
CX,50260
DIV
CX
MOV
BX,AX
; Sacar el resultado de la doble divisi¢n
MOV
DX,ResultHi
MOV
AX,ResultLo
CLC
SUB
AX,BX ; Restar factor de correcci¢n
SBB
DX,0
; Dividir entre 60 para obtener minutos y segundos.
MOV
CX,60
DIV
CX
MOV
Segundos,DL
DIV
CL
MOV
Minutos,AH
MOV
Horas,AL
; Establecer la bandera de AM/PM
MOV
PMFlag,0
CMP
Horas,12
JL
FinCalcula
INC
PMFlag
CMP
Horas,12
JE
FinCalcula
SUB
Horas,12
FinCalcula:
RET
Calcula2 EndP
; Pintar el valor de dos dígitos en la posición actual ES:DI
DespByte Proc Near
MOV CL,10
XOR AH,AH
DIV CL
ADD AX,3030h
MOV BL,AH
MOV AH,31 ; Blanco sobre azul
MOV ES:[DI],AX
ADD DI,2
MOV AL,BL
MOV ES:[DI],AX
ADD DI,2
RET
DespByte EndP
; Pintar el reloj por acceso directo a memoria
Despliega Proc Near
PUSH
ES
MOV
AX,0B800h
MOV
ES,AX
MOV
DI,138 ; Columna 80-11 de ancho=69*2 bytes
c/columna=138
MOV
AL,Horas
CALL
DespByte
MOV
AL,':'
MOV
ES:[DI],AX
ADD
DI,2
MOV
AL,Minutos
CALL
DespByte
MOV
AL,':'
MOV
ES:[DI],AX
ADD
DI,2
MOV
AL,Segundos
CALL
DespByte
MOV
AL,' '
MOV
ES:[DI],AX
ADD
DI,2
MOV
AL,'a'
CMP
PMFlag,1
JNE
MOV
ImpAMPM: MOV
ADD
MOV
MOV
POP
RET
Despliega EndP
ImpAMPM
AL,'p'
ES:[DI],AX
DI,2
AL,'m'
ES:[DI],AX
ES
; Rutina residente!!!
; Podría ser PROC
Inicio:
PUSHA
PUSHF
CALL
CALL
CALL
Salir:
POPF
POPA
IRET
porque es la
; Guardar todos los registros
; y además las banderas
LeeReloj
Calcula2
Despliega
; Restaurar banderas
; y registros
; Terminar rutina de interrupción; esto solamente
; interrupción 1Ch, que no tiene una función
predefinida. Si fuera
; otra, habría que saltar a la rutina que anteriormente
atendía la
; interrupción
; Parte no residente del programa; debe ponerse al final, para que se
use la
; Interrupción 27h
Inicializa:
; Ajustar DS
PUSH DS
PUSH CS
POP
DS
PUSH ES
; Apuntar ES al segmento 0
XOR
AX,AX
MOV
ES,AX
; Muy importante: Desactivar Interrupciones cuando vamos a
ajustar el vector
CLI
LEA
BX,Inicio
MOV
AX,CS
; Ajustar el vector de interrupción del Reloj: en BX el
desplazamiento de la
; rutina que atiende al reloj, en AX el segmento.
MOV
ES:[1Ch*4],BX
MOV
ES:[1Ch*4+2],AX
STI
; Restaurar ES
POP
ES
; DS:DX apuntan al final de la zona que va a quedar residente
LEA
DX,Inicializa
INT
27h
; Terminar pero dejar parte residente
END Start
http://www.sinergiaweb.com.mx/clases/asm9708/programa/relojres.asm
1.4 Estructura de un programa en ensamblador.
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.
http://www.monografias.com/trabajos11/lenen/lenen.shtml
FORMATO DE INSTRUCCIONES.
Un programa en lenguaje ensamblador es una serie de sentencias ejecutables
que le dicen al ensamblador que operaciones tiene que realizar.
Cada sentencia de lenguaje ensamblador esta compuesto de cuatro campos:
CAMPO
NOMBRE
CAMPO
OPERACIÓN
CAMPO
OPERANDO
CAMPO
COMENTARIO
Sin embargo, ciertas instrucciones del ensamblador no utilizan todos los
campos. El campo comentario existe para expresar propósitos o
documentación de programación interna y es opcional.
CAMPO NOMBRE:
El campo del nombre, algunas veces denominado el campo de rótulo, asigna
un nombre simbólico, a la dirección de comienzo de memoria real de una
instrucción del ensamblador. Esto permite al programador que referencie una
instrucción por nombre y elimine la necesidad de seguir la pista de direcciones
de las instrucciones, esto es especialmente útil al generar código reubicable. Al
utilizar una referencia simbólica, el programador permite al enlazador (linker)
seleccionar en que sitio de memoria será cargado el programa en lenguaje
ensamblador.
Aunque a cualquier instrucción se le puede dar un nombre, este campo
esta habitualmente reservado para aquellas instrucciones que serán
reverenciadas en las definiciones de datos, constantes, lazos, bifurcaciones y
llamadas a subrutinas.
Un nombre debe comenzar con un carácter alfabético y puede contener
hasta 31 caracteres, incluyendo:
· Todas las letras de la (A a la Z, a a la z)
· Dígitos numéricos del (0 al 9)
· Los símbolos especiales siguientes (-$.?@%)
Debe de tenerse precaución al seleccionar un nombre. No se puede utilizar
un nombre que coincida con una palabra reservada o directivo del
ensamblador. Si el nombre incluye un punto (.), entonces el punto debe ser el
primer carácter.
Un campo nombre puede ser un nombre simbólico que represente:
· Nombre de etiqueta
· Nombre de constantes
· Nombre de variables
· Nombre de procedimiento
· Nombre de macro
CAMPO OPERACION:
El campo de operación contiene un mnemotécnico para una instrucción real
del microprocesador. El mnemónico de operación hace el código más fácil de
leer y comprender y es solamente una tabla de conversión interna del valor
binario de código máquina real. Una operación o nemotécnico, puede
representar una instrucción máquina, macroinstrucción o pseudo-operación.
Ejemplo : INITAL: MOV AX, OH
INITAL es un rótulo y MOV es una operación.
Siguiendo al campo de operación se encuentra el campo de operando, cada
operación no solo le dice al ensamblador que instrucción debe ejecutar sino
cuantas operaciones se necesitan y de que tipo. Una operación puede
contener una referencia a una macro tal referencia indica al ensamblador como
procesar una secuencia predefinida de código.
El campo operación, esta representado por un mnemónico. Se tienen dos tipos
de mnemónicos:
Pseudo - operación
Código de operación
Directivas
=
macros.
Instrucciones =
programa.
(directivas)
(instrucciones)
la directiva nos sirve para definir, variables, constantes,
son los códigos que se ejecutan durante la ejecución del
CAMPO OPERANDO :
El campo operando contiene la posición o posiciones donde están los datos
que van hacer manipulados por la instrucción de la operación, si la instrucción
requiere uno o dos operados. Los operados están separados de la instrucción
por al menos un espacio en blanco. Si hay operaciones que no requieren
operados.
Cuando una operación requiere dos operados, el primer operando se
denomina operando destino y el segundo operando fuente. Operaciones de
transferencia de datos, registros, almacenamiento inmediato y almacenamiento
de memoria. Son ejemplos de instrucciones que requieren dos operandos por
ejemplo:
MOV AX, 8
Este es un ejemplo de operando inmediato. Aquí, el dato a ser manipulado
se incluye como operando fuente y se desplaza al registro AX, u operando
destino.
CAMPO COMENTARIO:
El campo comentario es él ultimo de los cuatro campos y puede ser uno de
los mas útiles. El campo comentario se utiliza para documentar internamente el
código fuente del ensamblador. Los comentarios son ignorados por el
ensamblador y son útiles solo al listar el código fuente. Si un comentario se
incluye con una instrucción de operación entonces debe estar separado del
último campo por al menos un espacio en blanco y comenzar con un punto y
coma (;).
Un comentario debe ser utilizado para describir aquellas líneas de código
fuente que no son comprensibles inmediatamente. Por ejemplo:
MOV AH, 45H
; PARAMETO PARA LEER UN CARACTER
Como se muestra, el comentario explica por que el registro AH esta siendo
cargado con 45H. En este caso, el 45H es utilizado para disparar la acción
apropiada cuando se llame a una interrupción.
Un programa bien documentado no tiene por que incluir comentarios en cada
instrucción y se recomienda:





No utilizar en los comentarios abreviados cuyo significado resulte poco
claro.
Comentar todas las definiciones de símbolos, reservas de memoria,
definición de constantes, propósito del programa, los subprogramas, etc.
Hacer comentarios escuetos, los detalles se adjuntan en documentos
apartes.
Comentar todos los puntos clave *no comentar instrucciones sin
dificultad en su comprensión.
Indicar en el comentario la tarea que se quiere ejecutar con una
instrucción o secuencia de instrucciones.
Los delimitadores que podemos usar en cada una de las líneas son:
: (Dos puntos) después de una etiqueta
(Espacio) entre el código de operación y operando
, (Coma) entre operando del mismo tipo
; (Punto y coma) precede un comentario
“FORMATO DE UN PROGRAMA”
Existen ciertas normas para crear un programa en lenguaje ensamblador.
La primera se refiere al formato interno de cada instrucción del lenguaje. Toda
línea de código debe digitarse bajo ciertas reglas, las cuales pueden
considerarse como la sintaxis propia del lenguaje. La segunda norma es el
formato externo del programa, que puede equipararse con una capa que
rodeara al programa para ayudar a definir su entorno.
EL FORMATO EXTERNO
El formato externo esta formado por varios comandos clave que permiten
establecer el entorno operativo del programa.
En el ensamblador se utilizan dos formatos básicos para desarrollar la
programación. En un método se utilizan modelos de memoria y, en el otro
definiciones de segmento completo. Los modelos de memoria son exclusivos
del programa MASM para ensamblador. Las definiciones de segmento
completo son comunes para casi todos los ensambladores.
El método que utiliza los modelos de memoria son más fáciles de usar, pero
las definiciones de segmento completo ofrecen mayor control de la tarea del
lenguaje ensamblador.
USO DE MODELOS:
PROGRAMA QUE DESPLIEGA UNA CADENA EN LA PANTALLA
; Nombre del programa
; Fecha de creación
; Autor
; Objetivo
; COMANDO DE ENSAMBLE
; COMANDO DE ENLACE
; COMANDO DE EJECUCION
; Define el modelo de memoria
;
. MODEL SMALL
. CODE
Empieza :
MOV AX, @DATA
MOV DS, AX
MOV DX, OFFSET MENSAJE
MOV AH, 9
INT 21H
MOV AX, 4c00h
INT 21h
.DATA
Mensaje DB 'Hola, .qué tal!.$'
.STACK
END Empieza
: EJ02CA03.ASM
: ABRIL 19 DE 1993
: J.A. Rojas Ponce
: Desplegar una cadena
: MASM EJ02CA03 ;
: LINK EJ02CA03 ;
: EJ02CA03 [ENTER]
; Modelo de memoria
; Area de código
; Etiqueta de comienzo de programa
; Inicializa Ds con la
; Dirección de @DATA
; Dirección de mensaje
; en DX para poder desplegarlo
; a través de la Int 21 de MS-DOS .
; regresa a MS-DOS por medio de la
; Función 4c.
; Segmento de datos
; Cadena a desplegar
; Se necesita una PILA.
; Fin del programa
El primer comando .MODEL SMALL, es una directiva simplificada que le
indica al ensamblador como serán accesadas las instrucciones y los datos (a
través de sus segmentos específicos).
El comando .CODE, también es una directiva simplificada, le indica al
ensamblador que el siguiente grupo de instrucciones es el código a ejecutar.
Las dos instrucciones siguientes lo único que hacen es regresar el control a
MS-DOS (después de ejecutar el programa) siguiendo ciertas normas, que en
este caso consisten en cargar el registro AX con el código 4C00H (código de
terminación del programa) y después hacer la indicación a través de la
interrupción 21H.
El comando .STACK indica que se necesita reservar un espacio de
memoria para las operaciones de pila, y finalmente el comando END Empieza
señala el final del bloque de código y por END el final del programa.
Para crear un programa ejecutable en MASM teclee los siguientes comandos
en la línea de interacción de MS-DOS:
C:\MASM Ej00ca03
C:\LINK Ej00ca03
DEFINICION DE SEGMENTO COMPLETO
Aquí un programa parece ser más largo pero esta más estructurado que en
el método de modelo para inicializar un programa.
El primer segmento definido es el segmento de PILA, A continuación el
segmento de DATOS y que sirve para definir cada uno de los datos a usar en
el programa. Y por ultimo el segmento de CODIGO.
; PROGRAMA EJEMPLO
STACK SEGMENT PARA ‘STACK’
DB
64 DUP
STACK ENDS
DATA SEGMENT PARA 'DATA'
MESAGE DB ‘AHORA LO QUE ABUNDA ES EL AMOR’,’$’
DATA ENDS
CODE SEGMENT PARA CODE
MAIN PROC FAR
ASSUME CS: CODE, DS: DATA, ES: DATA, SS: STACK
PUSH DS
SUB
AX,AX
PUSH AX
MOV AX, DATA
MOV DS, AX
MOV ES, AX
; RUTINA PARA IMPRIMIR LA CADENA
LEA
DX, MESAGE
MOV AH, 09
INT
21H
RET
MAIN ENDP
CODE ENDS
END
Para crear un programa ejecutable se puede utilizar el ensamblador Turbo
Asemblet, para esto teclee los siguientes comandos en la línea de interacción
de MS-DOS:
C:\TASM Ejemplo1
C:\TLINK Ejemplo1
Estructura de un programa en ensamblador
Ya hemos estudiado algunas partes del programa en lenguaje ensamblador. Sólo nos
falta conocer la parte más importante: las instrucciones. Pero antes de eso, veremos cual
es la estructura básica de un algoritmo en código ensambladora con la finalidad de ener
claro cual es la estructura de todos los elemento que acabamos de ver. Esto lo veremos
más a fondo cuando veamos todo lo concerniente a la programación.
Esta estructura contiene los siguientes elementos o partes que deben ser codificadas:
- Comentario descriptivo del programa (opcional, pero recomendable)
- Definir el microcontrolador que se usará (con las directrices LIST e INCLUDE).
- Introducir las opciones de compilación (que serán vistas más adelante)(opcional)
- Establecer las constantes que se usarán (con la directriz EQU).
- Reservar espacios de memoria (directriz RES) (si es necesario)
- Configurar los puertos
- Desarrollar el programa
- Poner comentarios
Y su estructura es:
Figura 41. Esquema de un programa
Hemos visto la estructura general. Ahora veremos la posición de los elementos del
código por columnas. Estas se dividen en cuatro:
-
Columna 1: Etiqueta. Las etiquetas se rigen por las siguientes normas:
· Debe situarse en la primera columna
· Debe contener únicamente caracteres alfanuméricos
· El máximo de caracteres es de 31
-
Columna 2:
-
Columna 3: Son los registros (f, l o k , b y w) donde se almacenarán los
resultados y con los que se operará
-
Columna 4: Comentario. Aquí se situará cualquier comentario personalizado
que deseemos. Estos son útiles para saber qué hace un programa sin tener que
descifrar el código entero. El compilador (ensamblador) ignorará todo texto más
allá del carácter punto y coma “;”. Estos comentarios generalmente se sitúan en
la cuarta columna para describir la acción de una línea de código, pero pueden
situarse en cualquier parte de programa para describir cualquier otro evento,
siempre que estén después del carácter “;” (semicolon en inglés).
Operación. En esta columna se situarán las instrucciones
Veamos más detenidamente cual es su posición:
Figura 42. Esquema de un programa por columnas
Normalmente las columnas son separadas por una tabulación. El espacio mínimo entre
dos columnas es de un carácter, que puede ser un espacio en vez de una tabulación.
http://usuarios.lycos.es/sfriswolker/pic/seis.htm
ver archivo: EstructuraEnsamblador.pdf
1.4.1
Data segment.
DS, Data Segment: Es el segmento destinado a ser usado junto con BX, SI y DI
para apuntar a una dirección de memoria. También puede ser usado con BP y
SP, pero hace falta expresarlo concretamente.
DS = Registro de segmento de datos. Contiene la dirección del segmento
de datos, es decir, el área de memoria donde se encuentran los datos
del programa.
DS: Data Segment (Segmento de Datos)
Este registro selecciona una sección de 64 Kb. que se
dedica generalmente a colocar en ella nuestras variables,
por lo cual toma su nombre: sección de memoria dedicada a
datos.
1.4.2
Snack segment.
SS, Stack Segment: El segmento de Stack; junto con SP apuntan a la última
posición que fue utilizada para "depositar" datos en el Stack.
SS = Registro de segmento de pila. Contiene la dirección del segmento de pila.
http://www.pablin.com.ar/computer/cursos/varios/introasm.htm
SS: Stack Segment (Segmento de Pila)
Este registro selecciona la región de 64 Kb. que va a
contener la pila del sistema. Como su nombre lo indica,
tendremos una estructura de datos, con política LIFO (Last
In, First Out = El último elemento en entrar, es el primero
en salir), con instrucciones básicas PUSH y POP para su
manejo. Esta estructura es usada por los programas de
aplicación, pero también por el procesador para el control
de instrucciones que lo requieren, tales como las llamadas
a subrutinas yla atención de interrupciones.
http://members.tripod.com/~MoisesRBB/arq80x86.html
1.4.3
Code segment.
CS = Registro de segmento de código. Contiene la dirección del
segmento de código, lo que son las instrucciones del programa.
CS: Code Segment (Segmento de Código)
Este registro selecciona el área de 64 Kb. que generalmente
dedicamos al código. En este caso, el CPU (específicamente,
el BIU), siempre toma las instrucciones de esta región de
memoria; por lo que cuando requerimos más de 64 Kb. de
código (instrucciones), este registro tendrá que moverse,
tomando distintos valores según recorremos distintas
regiones de memoria.
http://victorsanchez2.net/tutoriales/asm/asm001.htm
1.4.4
Instrucciones del programa.
La programación en lenguaje maquina es difícil, por ello se necesitan lenguajes
que permitan simplificar este proceso. Los lenguajes de bajo nivel han sido
diseñados para ese fin.
Estos lenguajes dependen de la maquina, es decir, dependen de un conjunto
de instrucciones especificas de la computadora.
Un lenguaje típico de bajo nivel es el lenguaje ensamblador. En este lenguaje
las instrucciones se escriben en códigos alfabéticos conocidos como
nemotécnicos (abreviaturas de palabras inglesas o españolas). Así, por
ejemplo, nemotécnicos típicos son:
ADD suma
MPY multiplicar
LDA cargar acumulador
SUB resta
DIV dividir
STO almacenar
Las palabras nemotécnicas son mucho más fáciles de recordar que las
secuencias de dígitos 0 y 1. Una instrucción típica en ensamblador puede ser:
ADD X, Y, Z
Esta instrucción significa que se deben sumar los números almacenados
en las direcciones x, y y almacenar el resultado en la dirección z.
El programa ensamblador traducirá la instrucción a código de maquina.
Por ejemplo:
ADD se puede traducir a 1110
x se puede traducir por 1001,
y 1010,
z por 1011.
La instrucción traducida sería:
1110 1001 1010 1011
Después que un programa ha sido escrito en lenguaje ensamblador, se
necesita un programa --llamado ensamblador-- que lo traduzca a código
máquina:
Programa fuente
( lenguaje ensamblador)
Ensamblador
Programa en
lenguaje de
maquina
Figura 1.12. Programa ensamblador.
http://www.monografias.com/trabajos15/el-software/el-software.shtml#
1.4.5
Directivas.
Directivas del lenguaje ensamblador
Además de los códigos para instrucciones de máquina, lenguajes de ensamblador tienen
directivas para ensamblar bloques de datos, y asignar localidades de dirección para
instrucciones o código.
Estos usualmente tienen una capacidad simbólica simple para definir valores como
expresiones simbólicas que se evalúan en tiempo de ensamble, haciendo posible escribir
código que es mas fácil de leer y entender.
Como la mayoría de lenguajes de computadora, comentarios textuales pueden ser agregados a
el código fuente [source code] que es ignorado por la computadora.
Estos también usualmente tienen un macro lenguaje integrado para hacer fácil generar piezas
complejas de código o datos.
En la práctica, la ausencia de comentarios y el reemplazo de símbolos con números actuales
hace la interpretación humana de código desensamblado considerable mas difícil que el
código fuente original.
http://www.geocities.com/SiliconValley/Haven/2037/documentos/Lenguaje
_Ensamblador.htm
DIRECTIVAS PARA LISTAR: PAGE Y TITLE
La directiva PAGE y TITLE ayudan a controlar el formato de un listado
de un programa en ensamblador. Este es su único fin, y no tienen
efecto sobre la ejecución subsecuente del programa.
PAGE. Al inicio de un programa, la directiva PAGE designa el numero
máximo de líneas para listar en una pagina y el numero máximo de
caracteres en una línea. Su formato general es:
PAGE [longitud][, ancho]
El ejemplo siguiente proporciona 60 líneas por pagina y 132
caracteres por línea:
PAGE 60, 132
El numero de líneas por pagina puede variar desde 10 hasta 255,
mientras que el numero de caracteres por línea desde 60 hasta 132.
La omisión de PAGE causa que el ensamblador tome PAGE 50, 80.
TITLE. Se puede emplear la directiva TITLE para hacer que un titulo
para un programa se imprima en la línea 2 de cada pagina en el
listado del programa. Puede codificar TITLE de una vez, al inicio del
programa. Su formato general es:
TITLE Texto.
Para el operando texto, una técnica recomendada es utilizar el nombre
del programa como se registra en el disco. Por ejemplo:
TITLE Prog1 Mi primer programa en ensamblador
DIRECTIVA SEGMENT
Un programa ensamblado en formato .EXE consiste en uno o mas
segmentos. Un segmento de pila define el almacén de la pila, un
segmento de datos define los elementos de datos y un segmento de
código proporciona un código ejecutable. Las directivas para definir un
segmento, SEGMENT y ENDS tienen el formato siguiente:
El enunciado SEGMENT define el inicio de un segmento. El nombre
del segmento debe estar presente, ser único y cumplir las
convenciones para nombres del lenguaje. EL enunciado ENDS indica
el final del segmento y contiene el mismo nombre del enunciado
SEGMENT. El tamaño máximo de un segmento es de 64K. El
operando de un enunciado SEGMENT puede tener tres tipos de
opciones: alineación, combinar y clase, codificadas en este formato:
nombre
SEGMENT
alineación
combinar
' clase '
TIPO ALINEACION. La entrada alineación indica el limite en el que
inicia el segmento. Para el requerimiento típico, PARA, alinea el
segmento con el limite de un párrafo, de manera que la dirección
inicial es divisible entre 16, o 10H. En ausencia de un operando hace
que el ensamblador por omisión tome PARA.
TIPO COMBINAR. La entrada combinar indica si se combina el
segmento con otros segmentos cuando son enlazados después de
ensamblar. Los tipos de combinar son STACK, COMMON, PUBLIC y
la expresión AT. Por ejemplo, el segmento de la pila por lo común es
definido como:
nombre
SEGMENT
PARA
STACK
Puede utilizar PUBLIC y COMMON en donde tenga el propósito de
combinar de forma separada programas ensamblados cuando los
enlaza. En otros casos, donde un programa no es combinado con
otros, puede omitir la opción o codificar NONE.
TIPO CLASE. La entrada clase, encerrada entre apóstrofos, es
utilizada para agrupar segmentos cuando se enlazan. Se utiliza la
clase 'code' para el segmento de códigos, 'data' por segmento de
datos y 'stack' para el segmento de la pila. El ejemplo siguiente define
un segmento de pila con tipos alineación, combinar y clase:
nombre
SEGMENT
PARA
STACK
'Stack'
DIRECTIVA ASSUME.
Un programa utiliza el registro SS para direccionar la pila, al registro
DS para direccionar el segmento de datos y el registro CS para
direccionar el segmento de código. Para este fin, usted tiene que
indicar al ensamblador el propósito de cada segmento en el programa.
La directiva para este propósito es ASSEME, codificada en el
segmento de código como sigue:
OPERACION
ASSUME
.
OPERANDO
SS:nompila, DS:nomsegdatos, CS: nomsegcodigo,. .
Los operandos pueden aparecer en cualquier orden. Al igual que otras
directivas, ASSUME es solo un mensaje que ayuda al ensamblador a
convertir código simbólico a código maquina; aun puede tener que
codificar instrucciones que físicamente cargan direcciones en registros
de segmentos en el momento de la ejecución.
1
PAGE 60,132
2
TITLE P04ASM1 ESTRUCTURA DE UN PROGRAMA
.EXE
3;------------------------------------------------------------------------------4 STACKSG SEGMENT PARA STACK 'Stack'
5
...
6 STACKSG ENDS
7;------------------------------------------------------------------------------8 DATASG SEGMENT PARA 'Data'
9
...
10 DATASG ENDS
11;------------------------------------------------------------------------------12 CODESG SEGMENT PARA 'Code'
13 BEGIN
PROC
FAR
14
ASSUME
SS:STACKSG,
DS:DATASG,CS:CODESG
15
MOV
AX, DATASG
;Obtiene la dirección
del segmento de datos
16
MOV
DS, AX
;Almacena dirección
en DS
17
...
18
MOV
AX, 4C00H
;Peticion
19
INT
21H
;Salida al DOS
20 BEGIN
ENDP
21 CODESG ENDS
22
END
BEGIN
http://www.itlp.edu.mx/publica/tutoriales/ensamblador/tem5_1_.htm
DIRECTIVAS SIMPLIFICADAS DE
SEGMENTOS
Los ensambladores de MicroSoft y de Borland proporcionan algunas
formas abreviadas para definir segmentos. Para usar estas
abreviaturas, inicialice el modelo de memoria antes de definir algún
segmento. El formato general (incluyendo el punto inicial) es:
.MODEL modelo de memoria
El modelo de memoria puede ser TINY, SMALL, MEDIUM, COMPACT
o LARGE. Los requisitos para cada modelo son:
Puede utilizar cualquiera de estos modelos para un programa
autónomo (esto es, un programa que no este enlazado con algún
otro). El modelo TINY esta destinado para uso exclusivo de programas
.COM, los cuales tienen sus datos, código y pila en un segmento. El
modelo SMALL exige que el código quepa en un segmento de 64K y
los datos en otro segmento de 64K. La directiva .MODELL genera
automáticamente el enunciado ASSUME necesario.
Los formatos generales (incluyendo el punto inicial) para las directivas
que define los segmentos de la pila, de datos y de código son:
.STACK [tamaño]
.DATA
.CODE [nombre]
Cada una de estas directivas hace que el ensamblador genere el
enunciado SEGMENT necesario y su correspondiente ENDS. Los
nombres por omisión de los segmentos (que usted no tiene que
definir) son STACK, DATA y TEXT (para el segmento de código).
La figura 4.3 proporciona un ejemplo haciendo uso de las directivas
simplificadas de segmento.
page 60,132
TITLE P04ASM2 (EXE) Operaciones de mover y sumar
;------------------------------------------------------------------------.MODEL SMALL
.STACK
.DATA
64 ;Se define la pila
;Se definen los datos
FLDA DW
250
FLDB DW
125
FLDC DW
?
;------------------------------------------------------------------------.CODE
BEGIN PROC
MOV
(Prog. anterior)
MOV
ADD
MOV
MOV
INT
BEGIN ENDP
END
;Se define el segmento de código
FAR
AX, @data
;Se asigna la dirección de DATASG
AX, FLDA
AX, FLDB
FLDC, AX
;Mover 0250 a AX
;Sumar 0125 a AX
;Almacenar suma en FLDC
AX, 4C00H
21H
;Salida a DOS
BEGIN
;Fin de procedimiento
;Fin de programa
http://www.itlp.edu.mx/publica/tutoriales/ensamblador/tem5_2_.htm
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.
http://www.monografias.com/trabajos11/lenen/lenen.shtml
1.5 Procedimiento de ensamble, enlace y ejecución.
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:\PASS32\BIN\>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.
http://www.monografias.com/trabajos11/lenen/lenen.shtml
PROCESO DE ENSAMBLE Y LIGADO DE UN PROGRAMA.
Las instrucciones simbólicas que codifica el lenguaje ensamblador son
conocidas como el programa fuente. El programa ensamblador es utilizado
para traducir el programa fuente en código máquina.
Se debe de crear el programa fuente en un editor, por ejemplo el editor de
pascal, el cual genera un archivo en código ASCII que debe ser grabado con la
extensión .ASM.
El archivo generado, es sólo un archivo de texto que no puede ejecutarse,
para esto primero debe ensamblarlo y enlazarlo.
1.- El paso de ensamble consiste en la traducción del código fuente en código
objeto y la generación de un archivo intermedio .OBJ ó módulo. Una de las
tareas del ensamblador es calcular el desplazamiento de cada elemento en el
segmento de datos y de cada instrucción en el segmento de código. El
ensamblador también crea un encabezado al frente del módulo .OBJ generado,
éste aún no está en forma ejecutable.
2.- El paso de enlace implica convertir el módulo .OBJ en un módulo de código
de máquina .EXE (ejecutable).
3.- El último paso es cargar el programa para su ejecución. El cargador
desecha el encabezado y crea un PSP inmediatamente antes del programa
cargando en memoria.
COMO ENSAMBLAR UN PROGRAMA FUENTE
El programa ensamblador de Microsoft es MASM.EXE, mientras que el
programa de Borland es TASM.EXE. Para teclear el comando para ejecutar
MASM o TASM en una línea de comando o por medio de peticiones. El
formato general para un comando o línea para ensamblar un programa es :
MASM/TASM[opciones] fuente [,objeto] [,listado] [,refcruzada]
[
]
= Son opcionales.
fuente- Es el nombre del archivo que se encuentracon la extension .ASM .
objeto.- Prergunta que nombre le voy a dar al archivo .OBJ.
listado.-Si se desea crear un archivo que contenga codigo fuente y codigo
objeto se debe especificar con la extensión LST.
FORMATO GENERAL PARA ENLAZAR
LINK/TLINK ARCHOBJ,ARCHEJE,[,ARCHAMPA] [,ARCHIBIB1]
LINK=Microsoft
TLINK=Borland
ARCHOBJ.- Identifica el archivo objeto que ha generado el ensamblador.
ARCHEJE.- Se utiliza para archivos ejecutables.
DIRECTIVAS DE ENSAMBLE
El lenguaje ensamblador permite usar diferentes enunciados que permiten
controlar la manera en que un programa ensambla y lista, llamados directivas.
Las directivas que usa el lenguaje ensamblador son:
PAGE
DD
.LIST
ASSUME
END
ERR
DW
COMMENT
PROC
DT
EQU
ENDP
COMM
LABEL
DQ
DATA
DATA
GROUP
INCLUDE
SEGMENT
CREF
ORG
PROCED
TITLE
DFCONST
.MODEL
ENDS
.ALPHA
DIRECTIVAS DE DEFINICIÓN DE DATOS (DB,DW,DD,LABEL,EQU,ETC.)
DB (definir byte) .- Inicializa un byte completo.
Ejemplo :
HOLA
MESA
CARACTER
MENSAJE
PERSONA
HOY
TABLA
DIVERSOS
DB
DB
DB
DB
DB
DB
DB
DB
23
0AH
‘G’
‘SOCIEDAD DE CERRO AZUL’
0,1,2,3,4,5,6,7,8,9
45 DUP (‘STACK’)
50 DUP (03CH)
‘YES’,34,0FADH
DW(Definir palabra).- Se utiliza para definir una variable o tabla (palabra).
Ejemplo :
TEST1
TEST2
TEST3
TEST4
TEST5
TEST6
DW
DW
DW
DW
DW
DW
1234
0ABCDH
1,22,333,4444
23,112
23 DUP (100H)
50 DUP ( ?)
DD(Definir doble palabra).- Se utitliza para definir una variable o tabla para
inicializar una función de memoria.
Ejemplo :
CIELO
DD
ROSA
DD
FLOR
DD
SUMA
DD
REALES DD
DECIMAL DD
TABLA
DD
FRACC
DD
0FFFFFFFFH
0H
1,22,333,4444,55555
45H + 23H
2.17654
4.567E12
50 DUP (03CH)
0.12345
DQ (Definir cuadruple palabra).-Iniacializa 4 palabras. Acepta valores de
constantes,numéricos,tablas.
Ejemplo :
TABLA
MULTI
SUMA
LARGO
DQ
DQ
DQ
DQ
100,2000,30000,400000
1000 DUP (45.678)
-6.345E -5 + 5.0001E45
7989*12H
DT (Definir decabyte).-Inicializa 10 bytes de asignación de mamoria.
Ejemplo :
TABLA
MULTI
SUMA
LARGO
DT
DT
DT
DT
100,2000,30000,500000
1000 DUP (45.678)
-6.345 E -5 + 5,0001E45
7989*12
DBIT (Bit).- Define tipo de bits.
TEST1
TEST2
TEST3
TEST4
DBIT
DBIT
DW
DW
0001B
011001B
1B,0B,1B
0B
EQU.- Inicializa una variable con un valor especifico.
Ejemplo :
SUMA
DIEZ
...
EQU
EQU
CONTADOR
10
INC SUMA
ADD SUMA,DIEZ
ALPHA.- Ordena alfabeticamente los segementos. Se coloca al inicio del
programa para listar los elementos en forma ordenada.
PUBLIC.- Se utiliza para enlazar segmentos dentro de un programa o
programas externos.
Formato :
Programa que llama :
DSEG1
SEGMENT
PARA ‘CODE’
PUBLIC
CONVAL
...
CONVAL DW ?
DSEG1 ENDS
Subprograma llamado : EXTRN (NOM : TIPO )
EXTRN
CONVAL : FAR
DSEG2
SEGMENT PARA ‘CODE’
...
MOV
...
DSEG2 ENDS
ORG.- Nos permite indicar la dirección especfica de segementos de memoria.
Sirve para cambiar la dirección inicial de localidades, dandole una dirección
especifica de los segmentos.
Ejemplo :
ORG
FLDX
FLDY
FLDY2
ORG
0
DB ?
DW ?
DB ?
$+5
00
01
02
04
COMMENT.- Sirve para delimitar comentarios.
Ejemplo :
COMMENT DELIMITADOR DE COMENTARIO
...
DELIMITADOR DE COMENTARIO
NOMBRE GROUP NOM-SEG,....- Ayuda a agrupar con un nombre a varios
segmentos.
Ejemplo :
GROUP
SEG1
ASSUME
...
SEDG1
SEG2
ASSUME
...
SEG
GROUP NOM-SEG1SEG2
SEGMET PARA ‘DATA’
DS : GROUPX
ENDS
SEGMENT PARA ‘DATA’
DS : GROUPX
ENDS
LABEL.- Redefine el atributo de una variable.
Formato :
Nombre
REDEFB
REDEFW
FIELDB
LABEL
Especificador
DW 2532H
LABEL WORD
DB 25H
DB 32H
.
.
.
MOV AL,REDEFB
MOV BX,REDEFW
DIRECTIVAS DE DEFINICIÓN DE MEMORIA (PROC, SEGMENT, ASSUME,
END, ETC.)
PROC.- Indica la definición de un procedimiento pude llevar un atributo FAR o
NEAR.
Formato :
NOMSEGTO
NOMPROC
...
NOMPROC
NOMSEGTO
SEGMENT
PROC FAR/NEAR
ENDP
ENDS
; CODE
; UN PROCEDIMIENTO
;
; DENTRO
; DEL SEGMENTO DE CÓDIGO
SEGMET (Directiva de memoria).- Nos indica que tanta memoria va a ocupar
y sirva para segmentar la memoria en pila, código, datos y extras.
Formato :
NOMBRE
.
.
NOMBRE
SEGMENT (OPCIONES)
ENDS
; INICIA EL SEGMENTO
; FIN DE SEGMENTO
END.-Indica fin de programa.
Formato :
END
ENDS.- Indica fin de segmento.
Formato :
ENDS
ENDP.- Indica fin de procedimiento.
Formato :
ENDP
ASSUME.- Se utiliza para direccionar cada uno de los registros del segmento
a la dirección del segmento (DS,SS,ES,FS,CS).
Formato :
ASSUME
CS : CODESG, DS. :DATASG, SS : STACK ;... ES : DATASG
DIRECTIVAS PARA LIGADO DE UN PROGRAMA
TLINK .- Convierte un programa fuente a un archivo .OBJ en un archivo .EXE. Se
puede teclear LINK o TLINK. Enlazando con una línea de comando o por medio de
peticiones. La línea de comando es :
LINK/TLINK archobj, archeje, [, archmapa] [,archbibl]




Archobj.-Identifica al archivo objeto generado por el ensamblador. El
enlazador supone la extensión .OBJ de modo que no tiene que
introducirla. Unidad, subdirectorio y nombre de archivo pueden ser
iguales o diferentes del archivo fuente.
Archeje.- Estipula que se genera un archivo .EXE. Unidad, subdirectorio
y nombre del archivo pueden ser iguales o diferentes del archivo fuente.
Archmapa.- Estipula que se genera un archivo con extensión MAP que
indica la ubicación relativa y el tamaño de cada segmento y cualquier
error que LINK haya encontrado. Un error común es el fallo al definir un
segmento de pila. Introducir CON (por consola) le indica al enlazador
que muestre el mapa en la pantalla ( en lugar de escribirlo en un disco)
de forma que se pueda ver el mapa inmediatamente para los errores.
Archbibl.- Estipula la opción de bibliotecas, que no necesita en estos
primeros pasos de programación en lenguaje ensamblador.
DIRECTIVAS DE CONTROL DE LISTADO
.LIST y .XLIST.- Se utilizan para controlar el listado del archivo.
.LIST.- Permite listar los códigod fuente y objeto.
.XLIST.-Indica hasta donde se detiene el listado del archivo.
Formato :
.LIST, .XLIST
Ejemplo:
.XLIST
MYCODE
MYPROC
SEGMENT PARA ‘CODE’
PROC FAR
ASSUME CS : MYCODE, DS : MYDATA,SS : STACK
PUSH
SUB
PUSH
PAGE.-Directiva para listar, inicializa la longitud y achura de cada página de
listado.
Formato:
PAGE [LONGITUD] , [ANCHO]
Ejemplo:
PAGE
60,132
TITLE.- Permite que sea introducido un título en la segunda línea de cada
página de listado.
Formato :
TITLE (cadena)
Ejemplo:
TITLE PROGRAMA EJEMPLO
SUBTTL CHEQUEO DE CODIGOS DE ERROR
STACK SEGMENT PARA STACK
DB
64 DUP (´MIPILA´)
STACK ENDS
....
FUNCIONAMIENTO INTERNO.
Enseguida se ilustra un ejemplo muy claro de cómo sería un programa en
Lenguaje Ensamblador.
Para sumar 5+ 7.
1. Necesitamos 3 casillas, dos para los datos 5 y 7 y uno para depositar el
resultado. 2. Definir las operaciones y su orden, así como obtener una
codificación adecuada
3. Introducir los datos en memoria.
Ocupamos una instrucción para llevar el contenido de una celda al acumulador
(o registro contenido en la CPU); otra para hacer la suma y otra para regresar
el contenido del acumulador a una celda de la memoria.
El formato de la instrucción para llevar el contenido de una celda al
acumulador(le llamaremos CARGA_AC) será como sigue:
CARGA_AC
Dirección
Donde: CARGA_AC = al nombre de la instrucción.
Dirección =celda de memoria cuyo valor queremos llevar al
acumulador
CARGA_AC, es el nombre mnemónico que daremos a la instrucción, debemos
asignarle un código numérico interno, sin importar ahora cual sea este, ocupará
el contenido de una celda de la memoria. Así mismo, la dirección será un
número que ocupará un lugar en otra celda. Es decir, CARGA_AC ocupará dos
celdas: Una para el código de la operación y otra para la dirección a la que
hace referencia.
GUARDA_AC, Dirección; que deposita el valor del acumulador en una celda
de la memoria(esta es la inversa de la anterior).
SUMA Dirección; que suma de memoria descrita por la dirección:
Ahora nuestro diccionario será como sigue:
INSTRUCCIÓN
CARGA_AC
CODIGO LONG. DE LA
INTERNO INSTRUCCIÓN
21
2
GUARDA_AC
96
2
SUMA
57
2
RESTA
42
2
Ahora escribiremos el programa en forma tabular. En la parte izquierda del
renglón pondremos la instrucción mnemónica seguida de la dirección a la que
haga referencia, luego pondremos su equivalente en el código interno extraído
del diccionario y, por último, describiremos el renglón para lo que sigue
suponemos que la celda 21 contiene un 5 y que la celda 22 contiene un 7.
INSTRUCCIÓN DIRECCION CODIGO COMENTARIOS
CARGA_AC
21
2121
Colocamos el
1er. Núm. En el
acumulador
SUMA
22
5722
Efectuamos la
suma
Dejamos el
resultado en la
casilla 23
GUARDA_AC
23
9623
ALTO
…..
70
finaliza
ALTO= Instrucción nueva para lograr que cuando se ejecute la secuencia,
llegue a su fin. Esta instrucción toma una sola casilla de memoria, ya que no
requiere hacer referencia a algunas direcciones.
Observemos dos nuevos programas; uno escrito en lenguaje mnemónico y otro
escrito en lenguaje numérico. Llamaremos programa fuente al primero y
programa objeto al segundo.


PROGRAMA FUENTE: Esta escrito en un lenguaje cercano al del ser
humano.
PROGRAMA OBJETO: Este ya está traducido al lenguaje que habla la
máquina.
En este caso escribimos ambos programas, pero en un caso general, el
programador escribirá el programa fuente y la computadora lo traducirá al
lenguaje objeto.
PASOS PARA EJECUCCION DE UN PROGRAMA
El programa objeto, entonces es: "21215722962370" que, obviamente,
ininteligible para un ser humano. Este programa funciona para sumar cualquier
par de números, siempre y cuando resida en las casillas 21y22.
Ahora introduciremos el programa en la memoria de la computadora, para que
pueda ejecutarse luego. ¿en que sección de la memoria lo vamos a cargar?,
decidimos hacerlo a partir de la celda 10 (o cualquiera que este desocupada y
disponga de suficientes celdas secuenciales vacías). La forma en que quedaría
nuestro programa objeto en la memoria es:
Cod. 21 21 57 22 96 23 70
05 07 ¿ ….
Dir.
10 11 12 13 14 15 16 …. 21 22 23 ….
Mem.
Ya cargado nuestro programa objeto a partir de la celda 10 de la memoria,
tenemos que encontrar un procedimiento para lograr que la computadora
comience la ejecución del mismo y así poder obtener los resultados deseados.
La unidad de control (UC) ejecutará el programa de la siguente forma:
1. Cuando el programa empieza a partir de la celda 10, indicaremos a la
unidad de control que esta celda contiene las primeras instrucciones por medio
de un apuntador que recibe el nombre de CONTADOR DE PROGRAMA(CP).
Este es un paso externo, no forma parte del programa.
2. La unidad de control ejecutará el paso a) e irá a la casilla 10 para leer su
contenido que es 21.
3. La unidad de control ejecutará el paso b) con lo que decodifica el 21 recién
leído y determina que se trata de una operación CARGA_AC.
4. La unidad de control ejecutará el paso c) con lo que efectuará la operación
de carga. Para esto la computadora debe ir a la celda 11 y extraer su
contenido, pero ahora ya no lo considerará como instrucción, sino como
dirección, por lo cual irá a la celda 21 para extraer el valor que contenga(que es
5). Esta instrucción completa "21 21" puede leerse así: "Carga el acumulador
con el valor que esté contenido en la celda cuya dirección aparece a la derecha
de donde estás leyendo ahora.
5. La unidad de control ejecuta el paso d) para luego ejecutar todo el ciclo de
nuevo. Esto es un ciclo infinito, que sólo terminará cuando se ejecute la
instrucción ALTO. El CP=12, o sea apuntará a la celda 12.
6. Se ejecutará(por segunda vez) el paso a) de la unidad de control. Como
CP=12, se leerá esa celda, que contiene un 57.
7. Se decodifica esa instrucción que resulta ser SUMA_AC, por lo que el CP
se preparará para apuntar a la siguiente celda.
8. Se ejecuta la instrucción 57 con lo que se añade el contenido de la celda 22
al acumulador(la dirección 22 reside en la celda 13, que es a la que
actualmente apunta el contador de programa como resultado del paso
anterior).Ahora el acumulador contendrá un 12 (o sea 5+7).
9. El CP se actualiza para apuntar a la celda 14, en la cual reside el código de
la siguiente instrucción.
10. Se lee la celda número 14 y se extrae su contenido, 96.
11. Se decodifica la instrucción, que resulta ser GUARDA_AC, por lo que CP
se alista para apuntar a la siguiente celda, que contendrá la dirección de la
celda en donde se va a guardar el contenido del acumulador.
1.6 Entorno de programación.
Unidad 2. Elementos del lenguaje
2.7 Instrucciones lineales.
2.7.1 Movimiento.
Movimiento de datos
En todo programa es necesario mover datos en la memoria y en los registros de la UCP;
existen diversas formas de hacer esto: puede copiar datos de la memoria a algun
registro, de registro a registro, de un registro a una pila, de la pila a un registro,
transmitir datos hacia dispositivos externos asi como recibir datos de dichos
dispositivos.
Este movimiento de datos está sujeto a reglas y restricciones. Algunas de ellas son las
que se citan a continuación.
No es posible mover datos de una localidad de memoria a otra directamente, es
necesario primero mover los datos de la localidad origen hacia un registro y luego del
registro a la localidad destino.
No se puede mover una constante directamente a un registro de segmentos, primero se
debe mover a un registro de la UCP.
Es posible mover bloques de datos por medio de las instrucciones movs, que copia una
cadena de bytes o palabras; movsb que copia n bytes de una localidad a otra; y movsw
copia n palabras de una localidad a otra. Las dos últimas instrucciones toman los valores
de las direcciones definidas por DS:SI como grupo de datos a mover y ES:DI como
nueva localización de los datos.
Para mover los datos tambien existen las estructuras llamadas pilas, en este tipo de
estructuras los datos se introducen con la instrucción push y se extraen con la
instrucción pop
En una pila el primer dato introducido es el último que podemos sacar, esto es, si en
nuestro programa utilizamos las instrucciones:
PUSH AX
PUSH BX
PUSH CX
Para devolver los valores correctos a cada registro al momento de sacarlos de la pila es
necesario hacerlo en el siguiente orden:
POP CX
POP BX
POP AX
Para la comunicación con dispositivos externos se utilizan el comando out para mandar
información a un puerto y el comando IN para leer información recibida desde algun
puerto.
La sintaxis del comando OUT es:
OUT DX,AX
Donde DX contiene el valor del puerto que se utilizará para la comunicación y AX
contiene la información que se mandará.
La sintaxis del comando IN es:
IN AX,DX
Donde AX es el registro donde se guardará la información que llegue y DX contiene la
dirección del puerto por donde llegará la información.
http://usuarios.lycos.es/patricio/ensam/ensam2.htm
La orden MOV.
La función de la orden MOV es, como su nombre da a entender, "mover" un
valor. Pongamos un ejemplo:
MOV AX,BX
Esta orden en lenguaje Ensamblador, copiará el contenido de BX en AX,
conservando el valor de BX. He aquí algún ejemplo más:
MOV AX,DS
MOV ES,AX
MOV DX,AX
MOV AL,DH
Como se ve, no se puede realizar MOV AL,BX, ya que en AL no cabe BX
También se puede introducir un valor directamente en un registro. Sería
el caso de:
MOV AX,0FEA2h
MOV BL,255
MOV DH,01110101b
Pongamos ejemplos de cómo se utiliza la numeración. El primero
era un número hexadecimal, el segundo decimal, que no va acompañado por
nada para indicarlo, y el tercero binario, con la b al final. A veces,
para representar un número decimal, se pone una 'd' al final (p.ej., 10d)
Más utilidades de MOV. Podemos transferir bytes que estén en memoria
a un registro, o de un registro a memoria. Vayamos con los ejemplos:
MOV AX,[BX]
Y pongamos que en BX esté 0EEEEh. En vez de transferir a AX el valor
0EEEEh, le transferiremos el valor que haya en la posición de memoria
CS:BX; si CS por ejemplo vale 0134h y BX 03215h, transferiríamos el byte
que hay en 0134:03215h y el siguiente a AX.
Se puede hacer también al revés;
MOV [AX],CX
Escribiríamos en la dirección de memoria CS:AX el valor de CX.
Y también podremos usar valores numéricos:
MOV AX,[2325h] (lo que hay en CS:2325h)
MOV AX,DS:[2325h] (el valor en DS:2325h)
MOV AX,DS:DX (el valor en DS:DX)
MOV DX,CS:CX (a DX, valor en CS:CX)
MOV BX,CS:1241h (a BX, valor en CS:1241h)
Muchas veces, se utiliza Word Ptr o Byte Ptr, que aclaran el tamaño a
transferir:
MOV AL,BYTE PTR [BX+SI-30h]
MOV AX,WORD PTR [BX+DI]
Como acabamos de ver, es posible hacer "sumas" de valores al buscar
una dirección en memoria. Otros ejemplos serían:
MOV AX,[BX+3]
MOV [BP+SI],AH
Y para acabar este apartado, he aquí una tablilla de ejemplos sobre MOVs que se
pueden hacer:
º Formatos de la instrucción MOV º Ejemplos º
º MOV reg,reg º MOV AX,BX º
º MOV mem,reg º MOV [BX],AL º
º MOV reg,mem º MOV CH,[40FFh] º
º MOM mem,inmed º MOV BYTE PTR [DI],0 º
º MOV reg,inmed º MOV BX,0FFFFh º
º MOV segreg,reg16 º MOV DS,AX º
º MOV mem,segreg º MOV [SI],ES º
º MOV segreg,mem º MOV SS,[1234h] º
reg: registro mem:memoria inmed:número inmediato
segreg: registro de segmento reg16: registro de 16 bits
Y vista la orden MOV, seguimos adelante.
La instrucción de transferencia de datos por excelencia es:
MOV destino, fuente
entendiendo por fuente el contenido que se va a transferir a una
determinada zona o registro de memoria denominada destino.
Esta instrucción, por tanto, nos va a permitir transferir informacion
entre registros y memoria, memoria y registros y entre los propios
registros utilizando alguno de los diferentes modos de
direccionamiento. Con la instrucción MOV diremos que se pueden
realizar todo tipo de movimientos teniendo en cuenta las siguientes
restricciones:
1.- No se puede realizar una transferencia de datos entre dos
posiciones de memoria
directamente, por esta razón, siempre que queramos efectuarlas
tendremos que utilizar un registro intermedio que haga de puente.
Por ejemplo, para hacer la operacion DATO1 <-- DATO2, la
instrucción MOV DATO2,DATO1
sería incorrecta. Lo que sí sería correcto sería utilizar el registro DX, u
otro, como puente y hacer:
MOV DX,DATO1
MOV DATO2,DX
2.- Tampoco se puede hacer una transferencia directa entre dos
registros de segmento. Por eso, como en el caso anterior, si fuera
preciso se utilizaría un registro como puente.
3.- Asimismo, tampoco se puede cargar en los registros de segmento
un dato utilizando direccionamiento inmediato, es decir, una constante,
por lo que también habrá que recurrir a un registro puente cuando sea
preciso.
Una instrucción util pero no imprescindible es:
XCHG DATO1, DATO2
que intercambia los contenidos de las posiciones de memoria o
registros representadospor DATO1 y DATO2.
Por ejemplo, si queremos intercambiar los contenidos de los registros
AX y BX, podemos hacer:
MOV AUX, AX
MOV AX, BX
MOV BX, AUX
en donde AUX es una variable auxiliar que hace de puente, o
simplemente utilizar:
XCHG AX, BX
Las restricciones que presenta esta operación es que no se pueden
efectuar intercambios directamente entre posiciones de memoria ni
tampoco entre registros de segmento.
La instrucción XLAT tabla carga en el registro AL el contenido de la
posición [BX][AL], en donde el registro BX ha de apuntar al comienzo
de una tabla. Dichio de otra manera, AL hace de índice de la tabla y
de almacén destino del contenido de la tabla.
Por ejemplo, el siguiente programa:
DATOS SEGMENT
TABLA DB 2,3,5,8,16,23
DATOS ENDS
CODIGO SEGMENT
MOVE BX, OFFSET TABLA ; Inicializa BX con la dirección donde
comienza la tabla
MOVE AL, 5
XLAT TABLA
CODIGO ENDS
hace que al final el contenido de AL se 16 ya que es el 5to. elemento
de la tabla y AL antes de XLAT TABLA contenia el valor 5.
Para finalizar con las instrucciones de transferencia veremos un grupo
de tres instrucciones:
- LEA o cargar dirección efectiva.
- LDS o cargar el puntero en DS.
- LES o cargar el puntero en ES.
denominadas de transferencia de direcciones.
La primera, LEA, carga el desplazamiento u OFFSET correspondiente
al operando fuente en el operando destino. Por ejemplo, la instrucción
MOVE BX, OFFSET TABLA del ejemplo anterior sería equivalente a
LEA BX, TABLA.
La segunda, LDS, se utiliza para cargar el valor del segmento de una
variable en el registro DS y el desplazamiento correspondiente en el
registro o posición de memoria indicada en la instrucción. Por ejemplo,
la instrucción LDS BX, NUM1 haría esquemáticamente lo siguiente:
La tercera y ultima de las instrucciones, LES, es similar a LDS, con la
única salvedad de que el valor del segmento se carga sobre el registro
de segmento ES en vez del DS.
2.7.2 Pila.
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
 INSTRUCCIONES DE MANEJO DE LA PILA.
 POP (extraer de la pila)
Sintaxis: POP destino
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere el elemento palabra que se encuentra en lo alto de la pila (apuntado
por SP) al operando destino que a de ser tipo palabra, e incrementa en dos el registro
SP. La instrucción POP CS, poco útil, no funciona correctamente en los 286 y
superiores.
Ejemplos:
pop
pop
ax
pepe
 PUSH (introduce en la pila)
Sintaxis: PUSH origen
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Decrementa el puntero de pila (SP) en 2 y luego transfiere la palabra
especificada en el operando origen a la cima de la pila. El registro CS aquí sí se puede
especificar como origen, al contrario de lo que afirman algunas publicaciones.
Ejemplo:
push
cs
 POPF (extrae los indicadores de la pila)
Sintaxis: POPF
Indicadores:
OF
x
DF
x
IF
x
TF
x
SF
x
ZF
x
AF
x
PF
x
CF
x
Traslada al registro de los indicadores la palabra almacenada en la cima de la
pila; a continuación el puntero de pila SP se incrementa en dos.
 PUSHF (introduce los indicadores en la pila)
Sintaxis: PUSHF
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Decrementa en dos el puntero de pila y traslada a la cima de la pila el
contenido de los indicadores.
http://meltingpot.fortunecity.com/uruguay/978/libro/04.html
LA PILA
La pila es una especie de "almacén de variables" que se encuentra en una
dirección determinada de memoria.
Nos encontramos con dos órdenes básicas respecto a la pila, que
son PUSH y POP. La orden PUSH empuja una variable a la pila, y la orden POP
la saca. Sin embargo, no podemos sacar el que queramos, no podemos decir
"quiero sacar el valor de DX que he metido antes y que fue el cuarto que
metí", por ejemplo.
La estructura de la pila se denomina LIFO, siglas inglesas que indican
'Last In First Out'. Esto significa que al hacer un POP, se sacará el
último valor introducido en la pila. Veamos esto con unos ejemplos:
PUSH DX ; Mete en la pila el contenido de DX
PUSH CX ; Y ahora el contenido de CX
POP AX ; Ahora saca el último valor introducido ( CX )
;y lo coloca en AX.
POP BP ; Y ahora saca en valor anterior introducido, que
;es el contenido de DX cuando hicimos el PUSH DX
;y se lo asigna a BP.
Ahora, una rutina algo más detallada:
MOV DX,0301h ; DX vale ahora 0301 hexadecimal.
PUSH DX ; Empuja DX a la pila. SP se decrementa en dos.
MOV DX,044C4h ; Ahora DX vale 044C4h
POP CX ; Y con esto, CX vale 0301 hexadecimal, el valor
que habíamos introducido con anterioridad.
Dijimos en la segunda línea: SP se decrementa en dos. Cuando por ejemplo
ejecutamos un .COM, SS es el segmento del programa (o sea, igual que CS,
y si no han sido modificados, DS y ES), y SP apunta al final, a 0FFFFh.
Cuando empujamos un valor a la pila, SP se decrementa en dos apuntando a
0FFFDh, y en esta dirección queda el valor introducido. Cuando lo saquemos,
se incrementará de nuevo en dos el valor de SP, y el valor se sacará de
la pila.
Se puede operar con esta instrucción con los registros AX, BX, CX, DX,
SI, DI, BP, SP, CS, DS y ES; sin embargo no se puede hacer un POP CS,
sólo empujarlo a la pila.
He aquí un ejemplo de lo que hace en realidad un POP en términos de MOVs;
aunque sea un gasto inútil de código, tiene su aplicación, por ejemplo, para
saltarse la heurística en un antivirus, que busca un POP BP y SUB posterior.
Partamos de que hay cierto valor en la pila que queremos sacar.
MOV BP,SP ; Ahora BP es igual al offset al que apunta SP
MOV BP,Word ptr [BP] ; Y ahora BP vale el contenido del offset al
;que apunta, que al ser el offset al que apunta
;el de pila, será el valor que sacaríamos
;haciendo un POP BP.
ADD SP,2 ; Para acabarlo, sumamos dos al valor de offset
;de la pila.
Y esto es lo que hace un POP BP, simplemente. Para ver lo que hace un PUSH
no habría más que invertir el proceso. Veámoslo.
SUB SP,2
MOV BP,SP
MOV Word ptr[BP],DX
Como última recomendación, hay que tener bastante cuidado con los PUSH
y POP, sacar tantos valores de la pila como se metan, y estar pendiente de
que lo que se saca es lo que se tiene que sacar. La pila bien aprovechada
es fundamental para hacer programas bien optimizados, ya que entre otras
cosas las instrucciones PUSH y POP solo ocupan un byte.
Es por ejemplo mucho mejor usar un PUSH al principio y un POP al final
en vez de dejar partes de código para almacenar variables, más velocidad
y menos tamaño.
Y finalmente, hay otras dos órdenes interesantes respecto a la pila,
PUSHF y POPF, que empujan el registro (16 bits) de flags y lo sacan,
respectivamente.
2.7.3 Matemáticos.
Instrucciones aritméticas
Las cuatro operaciones aritméticas básicas son suma, resta, multiplicación y división.
La mayoría de las computadoras proporcionan instrucciones para
las cuatro operaciones. Algunas computadoras pequeñas sólo tienen las instrucciones
suma y, tal vez, resta. La multiplicación y la división deben generarse mediante
subrutinas del software. Las cuatro operaciones aritméticas básicas son suficientes para
formular soluciones a problemas científicos cuando se expresan en términos de métodos
de análisis numérico.
En la tabla 8-7 se proporciona una lista de las instrucciones aritméticas típicas. La
instrucción de incrementar suma 1 al valor almacenado en un registro o palabra de
memoria. Una característica común de las operaciones de incrementar, cuando se
ejecutan en registros de procesador, es que un número binario que contiene sólo dígitos
1, produce un resultado de solo dígitos 0 cuando se incrementa. La instrucción para
Decrementar resta 1 de un valor: almacenado en un registro o palabra de memoria. Un
número con sólo dígitos 0, produce un número con sólo dígitos 1 cuando se decrementa.
TABLA 8-7 Instrucciones aritméticas típicas
NOMBRE
MNEMONICO
Incrementar
INC
Decrementar
DEC
Sumar
ADD
Restar
SUB
Multiplicar
MUL
Dividir
DIV
Sumar con acarreo
ADDC
Restar con préstamo
SUBB
Negar (complemento a 2)
NEG
Las instrucciones sumar, restar, multiplicar y dividir pueden estar disponibles para
diferentes tipos de datos. Los tipos de datos que se considera que están en los registros
del procesador durante la ejecución de estas operaciones aritméticas, se incluyen en la
definición del código de operación. Una instrucción aritmética puede especificar datos
de punto fijo o flotante. datos binarios o decimales, datos de precisión única o de doble
precisión. Los diferentes tipos de datos se presentaron en el capítulo 3.
No es extraño encontrar computadoras con tres o más instrucciones de suma: una para
enteros binarios, una para operandos de punto flotante y una para operandos decimales.
Enseguida, se muestran los mnemónicos para tres instrucciones de suma que especifican
tipos de datos diferentes.
ADDI Sumar dos números enteros de punto flotante
ADDF Sumar dos números de punto flotante
ADDD Sumar dos números decimales en BCD.
Los algoritmos para operaciones con enteros, punto flotante y aritmética ~ decimal se
desarrollan en el capítulo 10.
La cantidad de bits en cualquier registro es de extensión finita y, por lo tanto, los
resultados de las operaciones aritméticas son de precisión finita. Algunas computadoras
proporcionan operaciones de hardware de doble precisión, en las cuales el tamaño de
cada operando es de dos palabras de memoria. La mayoría de las computadoras
pequeñas proporcionan instrucciones especiales para facilitar la aritmética de doble
precisión. Un flip-flop especial de acarreo se utiliza para almacenar el acarreo de una
operación. la instrucción "sumar con acarreo" realiza la suma de dos operandos más el
valor del acarreo del cálculo previo. De igual manera, la instrucción "restar con
préstamo" resta dos palabras y un préstamo que puede haberse producido de una
operación de resta previa. La instrucción negar forma el complemento a 2 de un
número, invirtiendo en forma efectiva el signo de un entero cuando se representa en
forma de complemento a 2 con signo.
http://members.fortunecity.es/roy8/cpu.htm
Las instrucciones ADD y SUB
Se trata de dos operadores que contiene cualquier lenguaje de
programación: la suma y la resta. Tienen dos operandos, uno de destino y
otro fuente. Para la suma, se suman los dos operandos y se almacena en
el primero (destino), y para la resta, se resta al primero el segundo,
almacenándose en destino, el primero. Aquí están algunos formatos de estas
instrucciones:
ADD AX,BX ; Sumaría AX y BX y lo guardaría en AX
ADD [AX],BX ; Suma el contenido de la dirección de AX a BX,
;y se almacena en la dirección de AX
ADD AX,[BX] ; Se suman AX y el contenido de la dirección de
;BX, y se almacena ‚esta suma en AX
ADD AX,3 ; Lo mismo pero utilizando un valor inmediato
;en vez de la BX señalada anteriormente.
SUB CL,DL ; Resta de CL el valor de DL, y se almacena en CL
SUB [CX],DX ; Se resta al contenido de la dirección de CX
;el valor de DX, y se almacena en la dir. de CX
SUB CX,23h ; Se resta de CX el valor 23h, y queda en CX el
;resultado
¿Y si el resultado excede lo que puede contener el byte, o la palabra?.
Esto se puede saber mediante los flags, que trataremos más adelante.
También es resaltable que separa con ; los comentarios. Bien,
ésta es la manera en Ensamblador de poner comentarios, como sería en Basic
la orden "REM", o en C la convención "/* [...] */"
5.-3.- NEG, NOT y operaciones lógicas
Neg pone el registro o el lugar al que apunta en memoria en negativo
según la aritmética de complemento a dos tal que : NEG AX o NEG [AX]
Not es la que, como vimos, "invierte" los valores de los bits. Y el
resto de operaciones lógicas también las vimos anteriormente. Pondremos ahora
tan sólo su sintaxis:
NOT SI ; (o Not AX, etc.,... o sea, con un registro)
NOT Word ptr es:[ax] ; Lo realiza sobre la palabra ( 2 bytes )
;que se encuentra en es:[ax]
AND AX,BX ; Efectúa un AND entre AX y BX, almacenando
;el resultado en AX ( siempre en el primer
;término )
AND [AX],BX ; Lo dicho, pero AX apunta a un lugar de
;memoria
AND AX,[BX]
AND Byte ptr [15],3 ; Un AND en la dirección :0015 con lo que
;haya ah¡ y el valor "3"
OR AX,BX
OR [AX],BX
OR Byte ptr [15],3
OR DH,55h ;También podría hacerse en el AND, se
;confrontan DH y 55h en un OR.
Y todo lo dicho para OR y AND vale para XOR, de tal manera
que las operaciones son realizables entre:
Registro y registro CX,DX
Lugar de memoria y registro [DX],BX
Registro y lugar de memoria AX,[SI]
Lugar de memoria y número word ptr ES:[AX],0D533h
Registro y número AX,0CD32h
5.-4.- Multiplicación y división, MUL y DIV
Estas operaciones multiplican al acumulador por el operando indicado.
Si el operando es de 8 bits (1 byte), el acumulador es AL. Si el
operando es de 16 bits, el acumulador es AX. El resultado se almacena
en AX o en el par DX-AX respectivamente, si el operando es de 8 bits o
16 bits.
También tendremos que diferenciar entre dos tipos de multiplicaciones
y divisiones que entiende el procesador. Los que comienzan con una I
operan con números con signo, si queremos usar números negativos,
y los que no, con números sin signo.
Visto esto, podremos decir que:
MUL Byte Ptr [CX]
Va a multiplicar el byte que hay en la dirección que marca CX por el
contenido que hay en AL, y una vez hecho esto, va a almacenarlo en AX.
MUL SI
Multiplicaría SI por el contenido de AX, almacenándose en el par AX-DX.
La palabra superior, de más valor, se devolvería en DX, y la inferior
en AX.
IMUL SI
Esto y el ejemplo anterior sería lo mismo, sólo que operando con
números con signo.
Para la división, el dividendo ha de estar en AX, y ser 16 bits por
tanto. El divisor se indica en el operando, por ejemplo en DIV BL; este
divisor estaría en BL. Se dividiría AX entre BL y el resultado quedaría en
AL, quedando el resto en AH. Vamos a ver algún ejemplo.
En la división de un número de dieciséis bits entre otro de 8 bits, el
cociente y resto serán de 8 bits (1 byte). El dividendo ha de estar en AX,
y el divisor es el operando de la instrucción, que puede ser un registro o
un sitio en la memoria, y se necesita poner lo de byte ptr.
O sea, sería tal que:
DIV CL o IDIV BYTE PTR ES:[BP]
El resultado se devuelve en AL, y el resto en AH. Si por ejemplo AX
valiese 501d y cl valiese 2, al hacer el DIV CL, en AL quedaría 255 y en AH
quedaría 1.
Se puede dividir también un número de 32 bits (4 bytes) entre otro de
16 bits (2 bytes), con lo que cociente y resto serían de 16 bits. El
dividendo estaría formado por el par DX/AX. Al hacer por ejemplo un:
DIV SI
Se dividiría DX-AX entre SI, almacenándose el resultado en AX, y el resto
en DX. Por ejemplo:
Si en DX está el valor 003Fh y en AX 5555h, el par sería 3F5555h, con lo
que al dividirlo por SI (que pongamos que vale 0CCC4h), se almacenaría en
AX el resultado y en DX el resto.
http://platea.pntic.mec.es/~jdelucas/ensamblador.htm
SUMA Y RESTA.
Las instrucciones ADD y SUB realizan sumas y restas sencillas de
datos binarios. Los números binarios negativos están representados
en la forma de complemento a dos: Invierta todos los bits del numero
positivo y sume 1. Los formatos generales para las instrucciones ADD
y SUB son:
Como en otras instrucciones, no existen operaciones directas de
memoria a memoria. El ejemplo siguiente utiliza el registro AX para
sumar WORDA a WORDB:
WORDA DW 123
;Define WORDA
WORDB DW 25
;Define WORDB
...
MOV AX, WORDA ;Mueve WORDA al AX
ADD AX, WORDB ;Suma WORDB al AX
MOV WORDB, AX ;Mueve AX a WORDB
La figura 6.1. proporciona ejemplos de ADD y SUB para el
procesamiento de valores en un byte y en una palabra. El
procedimiento B10ADD utiliza ADD para procesar bytes y el
procedimiento C10SUB utiliza SUB para procesar palabras.
TITLE
P13ADD (COM) Operaciones ADD y SUB
.MODEL SMALL
.CODE
ORG 100H
BEGIN:
JMP SHORT MAIN
;---------------------------------------------------------------------------BYTEA
DB
64H
;DATOS
BYTEB
DB
40H
BYTEC
DB
16H
WORDA DW
4000H
WORDB DW
2000H
WORDC DW
1000H
;---------------------------------------------------------------------------MAIN
PROC NEAR
;Procedimiento principal:
CALL
B10ADD
;Llama a la rutina ADD
CALL
C10SUB
;Llama a la rutina SUB
INT
21H
MAIN
ENDP
;
Ejemplos de suma (ADD) de bytes:
;---------------------------------------------------------------------------B10ADD PROC
MOV
AL, BYTEA
MOV
BL, BYTEB
ADD
AL, BL
;registro a registro
ADD
AL, BYTEC
;memoria a registro
ADD
BYTEA, BL
;registro a memoria
ADD
BL, 10H
;inmediato a registro
ADD
BYTEA, 25H
;inmediato a memoria
RET
B10ADD ENDP
;
Ejemplos de resta (SUB) de palabras:
;---------------------------------------------------------C10SUB PROC
MOV
AX, WORDA
MOV
BX, WORDB
SUB
AX,BX
;Registro a registro
SUB
AX,WORDC
;Memora de registro
SUB
WORDA, BX
;Registro de memoria
SUB
BX, 1000H
;Inmediato de registro
SUB
WORDA, 256H ;Inmediato de memoria
RET
C10SUB ENDP
END BEGIN
Desbordamientos
Este alerta con los desbordamientos en las operaciones aritméticas.
Ya que un byte solo permite el uso de un bit de signo y siete de datos
(desde -128 hasta +127), una operación aritmética puede exceder con
facilidad la capacidad de un registro de un byte. Y una suma en el
registro AL, que exceda su capacidad puede provocar resultados
inesperados.
 *** SUMA ***
 AAA (ajuste ASCII para la suma)
Sintaxis: AAA
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
?
ZF
?
AF
x
PF
?
CF
x
Convierte el contenido del registro AL en un número BCD no empaquetado.
Si los cuatro bits menos significativos de AL son mayores que 9 ó si el indicador AF
está a 1, se suma 6 a AL, 1 a AH, AF se pone a 1, CF se iguala a AF y AL pone sus
cuatro bits más significativos a 0.
Ejemplo:
add
aaa
al,bl
En el ejemplo, tras la suma de dos números BCD no empaquetados colocados
en AL y BL, el resultado (por medio de AAA) sigue siendo un número BCD no
empaquetado.
 ADC (suma con acarreo)
Sintaxis: ADC destino, origen
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Suma los operandos origen, destino y el valor del indicador de acarreo (0 ó 1)
y el resultado lo almacena en el operando destino. Se utiliza normalmente para sumar
números grandes, de más de 16 bits, en varios pasos, considerando lo que nos llevamos
(el acarreo) de la suma anterior.
Ejemplo:
adc
ax,bx
 ADD (suma)
Sintaxis: ADD destino, origen
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Suma los operandos origen y destino almacenando el resultado en el operando
destino. Se activa el acarreo si se desborda el registro destino durante la suma.
Ejemplos:
add
add
ax,bx
cl,dh
 DAA (ajuste decimal para la suma)
Sintaxis: DAA
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Convierte el contenido del registro AL en un par de valores BCD: si los cuatro
bits menos significativos de AL son un número mayor que 9, el indicador AF se pone a
1 y se suma 6 a AL. De igual forma, si los cuatro bits más significativos de AL tras la
operación anterior son un número mayor que 9, el indicador CF se pone a 1 y se suma
60h a AL.
Ejemplo:
add
daa
al,cl
En el ejemplo anterior, si AL y CL contenían dos números BCD
empaquetados, DAA hace que el resultado de la suma (en AL) siga siendo también un
BCD empaquetado.
 INC (incrementar)
Sintaxis: INC destino
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
-
Incrementa el operando destino. El operando destino puede ser byte o palabra.
Obsérvese que esta instrucción no modifica el bit de acarreo (CF) y no es posible
detectar un desbordamiento por este procedimiento (utilícese ZF).
Ejemplos:
inc
inc
inc
inc
al
es:[di]
ss:[bp+4]
word ptr cs:[bx+di+7]
***RESTA***
 AAS (ajuste ASCII para la resta)
Sintaxis: AAS
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
?
ZF
?
AF
x
PF
?
CF
x
Convierte el resultado de la sustracción de dos operandos BCD no
empaquetados para que siga siendo un número BCD no empaquetado. Si el nibble
inferior de AL tiene un valor mayor que 9, de AL se resta 6, se decrementa AH, AF se
pone a 1 y CF se iguala a AF. El resultado se guarda en AL con los bits de 4 a 7 puestos
a 0.
Ejemplo:
sub
aas
al,bl
En el ejemplo, tras la resta de dos números BCD no empaquetados colocados
en AL y BL, el resultado (por medio de AAS) sigue siendo un número BCD no
empaquetado.
 CMP (comparación)
Sintaxis: CMP destino, origen
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Resta origen de destino sin retornar ningún resultado. Los operandos quedan
inalterados, paro los indicadores pueden ser consultados mediante instrucciones de
bifurcación condicional. Los operandos pueden ser de tipo byte o palabra pero ambos de
la misma dimensión.
Ejemplo:
cmp
cmp
bx, mem_pal
ch,cl
 DAS (ajuste decimal para la resta)
Sintaxis: DAS
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Corrige el resultado en AL de la resta de dos números BCD empaquetados,
convirtiéndolo también en un valor BCD empaquetado. Si el nibble inferior tiene un
valor mayor que 9 o AF es 1, a AL se le resta 6, AF se pone a 1. Si el nibble mas
significativo es mayor que 9 ó CF está a 1, entonces se resta 60h a AL y se activa
después CF.
Ejemplo:
sub
das
al,bl
En el ejemplo anterior, si AL y BL contenían dos números BCD
empaquetados, DAS hace que el resultado de la resta (en AL) siga siendo también un
BCD empaquetado.
 DEC (decrementar)
Sintaxis: DEC destino
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
-
Resta una unidad del operando destino. El operando puede ser byte o palabra.
Obsérvese que esta instrucción no modifica el bit de acarreo (CF) y no es posible
detectar un desbordamiento por este procedimiento (utilícese ZF).
Ejemplo:
dec
dec
ax
mem_byte
 NEG (negación)
Sintaxis: NEG destino
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Calcula el valor negativo en complemento a dos del operando y devuelve el
resultado en el mismo operando.
Ejemplo:
neg
al
 SBB (resta con acarreo)
Sintaxis: SBB destino, origen
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Resta el operando origen del operando destino y el resultado lo almacena en el
operando destino. Si está a 1 el indicador de acarreo además resta una unidad más. Los
operandos pueden ser de tipo byte o palabra. Se utiliza normalmente para restar
números grandes, de más de 16 bits, en varios pasos, considerando lo que nos llevamos
(el acarreo) de la resta anterior.
Ejemplo:
sbb
sbb
ax,ax
ch,dh
 SUB (resta)
Sintaxis: SUB destino, origen
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Resta el operando destino al operando origen, colocando el resultado en el
operando destino. Los operandos pueden tener o no signo, siendo necesario que sean del
mismo tipo, byte o palabra.
Ejemplos:
sub
sub
al,bl
dx,dx
*** MULTIPLICACION ***
 AAM (ajuste ASCII para la multiplicación)
Sintaxis: AAM
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
?
Corrige el resultado en AX del producto de dos números BCD no
empaquetados, convirtiéndolo en un valor BCD también no empaquetado. En AH sitúa
el cociente de AL/10 quedando en AL el resto de dicha operación.
Ejemplo:
mul
aam
bl
En el ejemplo, tras el producto de dos números BCD no empaquetados
colocados en AL y BL, el resultado (por medio de AAA) sigue siendo, en AX, un
número BCD no empaquetado.
 IMUL (multiplicación entera con signo)
Sintaxis: IMUL origen (origen no puede ser operando inmediato en 8086, sí en
286)
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
?
ZF
?
AF
?
PF
?
CF
x
Multiplica un operando origen con signo de longitud byte o palabra por AL o
AX respectivamente. Si origen es un byte el resultado se guarda en AH (byte más
significativo) y en AL (menos significativo), si origen es una palabra el resultado es
devuelto en DX (parte alta) y AX (parte baja). Si las mitades más significativas son
distintas de cero, independientemente del signo, CF y OF son activados.
Ejemplo:
imul
imul
bx
ch
 MUL (multiplicación sin signo)
Sintaxis: MUL origen (origen no puede ser operando inmediato)
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
?
ZF
?
AF
?
PF
?
CF
x
Multiplica el contenido sin signo del acumulador por el operando origen. Si el
operando destino es un byte el acumulador es AL guardando el resultado en AH y AL,
si el contenido de AH es distinto de 0 activa los indicadores CF y OF. Cuando el
operando origen es de longitud palabra el acumulador es AX quedando el resultado
sobre DX y AX, si el valor de DX es distinto de cero los indicadores CF y OF se
activan.
Ejemplo:
mul
mul
mul
byte ptr ds:[di]
dx
cl
*** DIVISION ***
 AAD (ajuste ASCII para la división)
Sintaxis: AAD
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
?
Convierte dos números BCD no empaquetados contenidos en AH y AL en un
dividendo de un byte que queda almacenado en AL. Tras la operación AH queda a cero.
Esta instrucción es necesaria ANTES de la operación de dividir, al contrario que AAM.
Ejemplo:
aad
div
bl
En el ejemplo, tras convertir los dos números BCD no empaquetados (en AX)
en un dividendo válido, la instrucción de dividir genera un resultado correcto.
 DIV (división sin signo)
Sintaxis: DIV origen (origen no puede ser operando inmediato)
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
?
ZF
?
AF
?
PF
?
CF
?
Divide, sin considerar el signo, un número contenido en el acumulador y su
extensión (AH, AL si el operando es de tipo byte o DX, AX si el operando es palabra)
entre el operando fuente. El cociente se guarda en AL o AX y el resto en AH o DX
según el operando sea byte o palabra respectivamente. DX o AH deben ser cero antes de
la operación. Cuando el cociente es mayor que el resultado máximo que puede
almacenar, cociente y resto quedan indefinidos produciéndose una interrupción 0. En
caso de que las partes más significativas del cociente tengan un valor distinto de cero se
activan los indicadores CF y OF.
Ejemplo:
div
div
bl
mem_pal
 IDIV (división entera)
Sintaxis: IDIV origen (origen no puede ser operando inmediato)
Indicadores:
OF
?
DF
-
IF
-
TF
-
SF
?
ZF
?
AF
?
PF
?
CF
?
Divide, considerando el signo, un número contenido en el acumulador y su
extensión entre el operando fuente. El cociente se almacena en AL o AX según el
operando sea byte o palabra y de igual manera el resto en AH o DX. DX o AH deben
ser cero antes de la operación. Cuando el cociente es positivo y superior al valor
máximo que puede almacenarse (7fh ó 7fffh), o cuando el cociente es negativo e
inferior al valor mínimo que puede almacenarse (81h u 8001h) entonces cociente y resto
quedan indefinidos, generándose una interrupción 0, lo que también sucede si el divisor
es 0.
Ejemplo:
idiv
idiv
bl
bx
*** CONVERSIONES***
 CBW (conversión de byte en palabra)
Sintaxis: CBW
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Copia el bit 7 del registro AL en todos los bits del registro AH, es decir,
expande el signo de AL a AX como paso previo a una operación de 16 bits.
 CWD (conversión de palabra a doble palabra)
Sintaxis: CWD
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Expande el signo del registro AX sobre el registro DX, copiando el bit más
significativo de AH en todo DX.
http://meltingpot.fortunecity.com/uruguay/978/libro/04.h
tml
2.7.4 Ajustes.
Las instrucciones INC y DEC:
Son las más básicas a la hora de hacer operaciones con registros: INC
incrementa el valor de un registro,o de cualquier posición en
memoria, en una unidad, y DEC lo decrementa. Veamos:
INC AX
Incrementa en uno el valor de AX
INC WORD PTR [BX+4]
Incrementa la palabra situada en CS:[BX+4] en uno.
DEC AX
Decrementa AX, le resta uno.
DEC WORD PTR [BX+4]
Decrementa la palabra situada en CS:[BX+4] en una unidad.
Estas dos instrucciones, equivalentes a "a++" en C, nos
servirán bastante como contadores para bucles.
http://platea.pntic.mec.es/~jdelucas/ensamblador.htm
2.7.5 Comparación.
INSTRUCCIONES DE COMPARACION
Nos van a servir para realizar las comparaciones, y son:
CMP y TEST
CMP compara dos registros, o un registro y una dirección de memoria.
Tiene el mismo formato que el SUB (por ejemplo CMP AX,BX), tan sólo que
ninguno de los registros es alterado. Si por ejemplo son iguales, el flag
de cero se pondrá en uno. Es en realidad un SUB del que no se almacena el
resultado.
TEST, comprobar, se puede realizar con el mismo formato de AND, ya que
es equivalente a ella, tan sólo que no se guarda el resultado, aunque sí se
modifican los flags.
Y en el próximo capítulo veremos cómo se aplican estos flags, y cómo
realizar los saltos comparativos.

LA INSTRUCCION CMP
La instrucción CMP pro lo común es utilizada para comparar dos
campos de datos, uno de los cuales están contenidos en un registro.
El formato general para CMP es:
| [etiqueta:] | CMP | {registro/memoria},
{registro/memoria/inmediato} |
El resultado de una operación CMP afecta la banderas AF, CF, OF,
PF, SF y ZF, aunque no tiene que probar estas banderas de forma
individual. El código siguiente prueba el registro BX por un valor cero:
X CMP BX, 00 ;Compara Bx con cero
JZ B50 ;Si es cero salta aB50
. ;(Acción si es diferente de cero)
.
B50: ... ;Destino del salto, si BX es cero
Si el BX tiene cero, cmp establece ZF a 1 y puede o no cambiar la
configuración de otras banderas. La instrucción JZ (salta si es cero)
solo prueba la bandera ZF. Ya que ZF tiene 1 (que significa una
condición cero), JZ transfiere el control (salta) a la dirección indicada
por el operando B50.
Observe que la operación compara el primer operando con el
segundo; por ejemplo, el valor del primer operando es mayor que,
igual o menor que el valor del segundo operando?

LA INSTRUCCION CMPS
CMPS compara el contenido de una localidad de memoria
(direccionada por DS:SI). Dependiendo de la bandera de dirección,
CMPS incrementa o disminuye también los registros SI y DI en 1 para
bytes, en 2 para palabras y en 4 para palabras dobles. La operación
establece las banderas AF, CF, OF, PF, SF y ZF.
Cuando se combinan con un prefijo REP y una longitud en el CX, de
manera sucesiva CMPS puede comparar cadenas de cualquier
longitud.
Pero observe que CMPS proporciona una comparación alfanumérica,
esto es, una comparación de acuerdo a con los valores ASCII.
Considere la comparación de dos cadenas que contienen JEAN y
JOAN. Una comparación de izquierda a derecha, tiene el resultado
siguiente:
J:J Iguales
E:O Diferentes (E es menor)
A:A Iguales
N:N Iguales
Una comparación de los 4 bytes termina con una comparación de N
con N (iguales). Ahora ya que los dos nombres no son idénticos, la
operación debe terminar tan pronto como la comparación entre 2
caracteres sea diferente.
Algunas derivaciones de CMPS son las siguientes:



CMPSB. Compara bytes.
CMPSD. Compara palabras dobles.
CMPSW. Compara palabras.
A continuación se muestra la codificación del uso del CMPS y sus
derivaciones:
TITLE P12CMPST (COM) Uso de CMPS para operaciones en
cadenas
.MODEL SMALL
.CODE
ORG
100H
BEGIN: JMP
SHORT MAIN
;------------------------------------------------------------------------------------NOM1 DB
'Assemblers' ;Elementos de datos
NOM2 DB
'Assemblers'
NOM3 DB
10 DUP (' ')
;------------------------------------------------------------------------------------MAIN PROC
NEAR
;Procedimiento principal
CLD ;Izquierda a derecha
MOV
CX, 10
;Iniciar para 10 bytes
LEA
DI, NOM2
LEA
SI, NOM1
REPE
CMPSB
;Compare NOM1:NOM2
JNE
G20
;No es igual, saltarlo
MOV
BH,01
;Igual, fijar BH
G20:
MOV
LEA
LEA
REPE
CX, 10
DI, NOM3
SI, NOM2
CMPSB
;Iniciar para 10 bytes
;Compare NOM2:NOM3
JE
MOV
G30
BL, 02
;Igual, salir
;No es igual, fijar BL
G30:
MOV
INT
MAIN ENDP
END
AX, 4C00H
21H
;Salir a DOS
BEGIN
2.8 Saltos.
Salto. Este término suele aplicarse sobre todo en programación, donde suele
distinguirse entre salto incondicional y salto condicional.
El salto incondicional sería aquella instrucción del programa que nos envía a
otra parte del programa sin tener en cuenta ninguna condición.
Al contrario, el salto condicional sería una, o varias instrucciones, que
comprobarían primero una condición; si esta condición es cierta salta a una
parte del programa, si es falsa a otra.
Una instrucción muy conocida en programación (por aparecer en muchos
lenguajes) es GOTO, que sería la instrucción de salto incondicional por
excelencia. No se suele recomendar mucho su uso (o nada), pues su
utilización implica la creación de un código fuente para el programa, poco
estructurado.
http://www.lawebdelprogramador.com/diccionario/mostrar.php?letra=J
Ver archivo:saltos.doc
Saltos, ciclos y procedimientos
Los saltos incondicionales en un programa escrito en lenguaje ensamblador están dados
por la instrucción jmp, un salto es alterar el flujo de la ejecución de un programa
enviando el control a la dirección indicada.
Un ciclo, conocido tambien como iteración, es la repetición de un proceso un cierto
número de veces hasta que alguna condición se cumpla. En estos ciclos se utilizan los
brincos condicionales basados en el estado de las banderas. Por ejemplo la instrucción
jnz que salta solamente si el resultado de una operación es diferente de cero y la
instrucción jz que salta si el resultado de la operación es cero.
Por último tenemos los procedimientos o rutinas, que son una serie de pasos que se
usaran repetidamente en el programa y en lugar de escribir todo el conjunto de pasos
unicamente se les llama por medio de la instrucción call.
Un procedimiento en ensamblador es aquel que inicie con la palabra Proc y termine con
la palabra ret.
Realmente lo que sucede con el uso de la instrucción call es que se guarda en la pila el
registro IP y se carga la dirección del procedimiento en el mismo registro, conociendo
que IP contiene la localización de la siguiente instrucción que ejecutara la UCP,
entonces podemos darnos cuenta que se desv'a el flujo del programa hacia la dirección
especificada en este registro. Al momento en que se llega a la palabra ret se saca de la
pila el valor de IP con lo que se devuelve el control al punto del programa donde se
invoc— al procedimiento.
Es posible llamar a un procedimiento que se encuentre ubicado en otro segmento, para
ésto el contenido de CS (que nos indica que segmento se está utilizando) es empujado
también en la pila.
http://usuarios.lycos.es/patricio/ensam/ensam2.htm
Hasta este punto los programas que hemos examinado han sido
ejecutados en forma lineal, esto es con una instrucción
secuencialmente a continuación de otra. Sin embargo, rara vez un
programa programable es tan sencillo. La mayoría de los programas
constan de varios ciclos en los que una serie de pasos se repite hasta
alcanzar un requisito especifico y varias pruebas para determinar que
acción se realiza de entre varias posibles.
Requisitos como este implican la transferencia de control a la dirección
de una instrucción que no sigue de inmediato de la que se esta
ejecutando actualmente. Una transferencia de control puede ser hacia
adelante, para ejecutar una serie de pasos nuevos, o hacia atrás, para
volver a ejecutar los mismos pasos.
Ciertas instrucciones pueden transferir el control fuera del flujo
secuencial normal añadiendo un valor de desplazamiento al IP.
Direcciones Corta, cercana y lejana
Una operación de salto alcanza una dirección corta por medio de un
desplazamiento de un byte, limitado a una distancia de -128 a 127
bytes. Una operación de salto alcanza una dirección cercana por
medio de un desplazamiento de una palabra, limitado a una distancia
de -32, 768 a 32, 767 bytes dentro del mismo segmento. Una dirección
lejana puede estar en otro segmento y es alcanzada por medio de una
dirección de segmento y un desplazamiento; CALL es la instrucción
normal para este propósito.
La tabla siguiente indica las reglas sobre distancias para la
operaciones JMP, LOOP y CALL. Hay poca necesidad de memorizar
estas reglas, ya que el uso normal de estas instrucciones en rara
ocasión causa problemas.
Etiquetas de instrucciones
Las instrucciones JMP, Jnnn (salto condicional) y LOOP requieren un
operando que se refiere a la etiqueta de una instrucción. El ejemplo
siguiente salta a A90, que es una etiqueta dada a una instrucción
MOV:
JMP A90
...
A90: MOV AH, 00
...
La etiqueta de una instrucción, tal como A90:, terminada con dos
puntos (:) para darle atributo de cercana - esto es, la etiqueta esta
dentro de un procedimiento en el mismo segmento de código.
Cuidado: Un error común es la omisión de los dos puntos. Note que
una etiqueta de dirección en un operando de instrucción (como JMP
A90) no tiene un carácter de dos puntos.
2.8.1 Incondicional.
 Incondicional
 CALL (llamada a subrutina)
Sintaxis: CALL destino
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere el control del programa a un procedimiento, salvando previamente
en la pila la dirección de la instrucción siguiente, para poder volver a ella una vez
ejecutado el procedimiento. El procedimiento puede estar en el mismo segmento (tipo
NEAR) o en otro segmento (tipo FAR). A su vez la llamada puede ser directa a una
etiqueta (especificando el tipo de llamada NEAR -por defecto- o FAR) o indirecta,
indicando la dirección donde se encuentra el puntero. Según la llamada sea cercana o
lejana, se almacena en la pila una dirección de retorno de 16 bits o dos palabras de 16
bits indicando en este último caso tanto el offset (IP) como el segmento (CS) a donde
volver.
Ejemplos:
dir
call
proc1
dd
call
0f000e987h
dword ptr dir
En el segundo ejemplo, la variable dir almacena la dirección a donde saltar. De
esta última manera -conociendo su dirección- puede llamarse también a un vector de
interrupción, guardando previamente los flags en la pila (PUSHF), porque la rutina de
interrupción retornará (con IRET en vez de con RETF) sacándolos.
 JMP (salto)
Sintaxis: JMP dirección o JMP SHORT dirección
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere el control incondicionalmente a la dirección indicada en el
operando. La bifurcación puede ser también directa o indirecta como anteriormente
vimos, pero además puede ser corta (tipo SHORT) con un desplazamiento comprendido
entre -128 y 127; o larga, con un desplazamiento de dos bytes con signo. Si se hace un
JMP SHORT y no llega el salto (porque está demasiado alejada esa etiqueta) el
ensamblador dará error. Los buenos ensambladores (como TASM) cuando dan dos
pasadas colocan allí donde es posible un salto corto, para economizar memoria, sin que
el programador tenga que ocuparse de poner short. Si el salto de dos bytes, que permite
desplazamientos de 64 Kb en la memoria sigue siendo insuficiente, se puede indicar con
far que es largo (salto a otro segmento).
Ejemplos:
jmp
jmp
etiqueta
far ptr etiqueta
 RET / RETF (retorno de subrutina)
Sintaxis: RET [valor] o RETF [valor]
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Retorna de un procedimiento extrayendo de la pila la dirección de la siguiente
dirección. Se extraerá el registro de segmento y el desplazamiento en un procedimiento
de tipo FAR (dos palabras) y solo el desplazamiento en un procedimiento NEAR (una
palabra). si esta instrucción es colocada dentro de un bloque PROC-ENDP (como se
verá en el siguiente capítulo) el ensamblador sabe el tipo de retorno que debe hacer,
según el procedimiento sea NEAR o FAR. En cualquier caso, se puede forzar que el
retorno sea de tipo FAR con la instrucción RETF. Valor, si es indicado permite sumar
una cantidad valor en bytes a SP antes de retornar, lo que es frecuente en el código
generado por los compiladores para retornar de una función con parámetros. También se
puede retornar de una interrupción con RETF 2, para que devuelva el registro de estado
sin restaurarlo de la pila.
http://meltingpot.fortunecity.com/uruguay/978/libro/04.html
Condicional
Las siguientes instrucciones son de transferencia condicional de control a la
instrucción que se encuentra en la posición IP+desplazamiento (desplazamiento
comprendido entre -128 y +127) si se cumple la condición. Algunas condiciones se
pueden denotar de varias maneras. Todos los saltos son cortos y si no alcanza hay que
apañárselas como sea. En negrita se realzan las condiciones más empleadas. Donde
interviene SF se consideran con signo los operandos implicados en la última
comparación u operación aritmetico-lógica, y se indican en la tabla como '±' (-128 a
+127 ó -32768 a +32767); en los demás casos, indicados como '+', se consideran sin
signo (0 a 255 ó 0 a 65535):
JA/JNBE
JAE/JNB
Salto si mayor (above), si no menor o igual (not below or equal), si CF=0 y ZF=0.
Salto si mayor o igual (above or equal), si no menor (not below), si CF=0.
+
+
Salto si menor (below), si no superior ni igual (not above or equal), si acarreo, si
+
JBE/JNA
Salto si menor o igual (not below or equal), si no mayor (not above), si CF=1 ó
ZF=1.
+
JCXZ
JE/JZ
JG/JNLE
JGE/JNL
JL/JNGE
JLE/JNG
JNC
JNE/JNZ
JNO
JNP/JPO
JNS
JO
JP/JPE
JS
Salto si CX=0.
JB/JNAE/JC CF=1.
Salto si igual (equal), si cero (zero), si ZF=1.
Salto si mayor (greater), si no menor ni igual (not less or equal), si ZF=0 y SF=0.
Salto si mayor o igual (greater or equal), si no menor (not less), si SF=0.
Salto si menor (less), si no mayor ni igual (not greater or equal), si SF<>OF.
Salto si menor o igual (less or equal), si no mayor (not greater), si ZF=0 y SF<>OF.
Salto si no acarreo, si CF=0.
Salto si no igual, si no cero, si ZF=0.
Salto si no desbordamiento, si OF=0.
Salto si no paridad, si paridad impar, si PF=0.
Salto si no signo, si positivo, si SF=0.
Salto si desbordamiento, si OF=1.
Salto si paridad, si paridad par, si PF=1.
Salto si signo, si SF=1.
±
±
±
±
SALTOS INCONDICIONALES
Empecemos por el salto sin condiciones, con el que podremos cambiar
el control a cualquier punto del programa. Sería como el "Goto" del Basic,
simplemente transferir el control a otro punto del programa. La orden es
JMP (de Jump, salto)
Si se recuerdan los registros CS:IP, se podrá ver qué es
lo que hace realmente la instrucción, y no es más que incrementar o
decrementar IP para llegar a la zona del programa a la que queremos
transferir el control (IP es el Offset que indica la zona de memoria
que contiene la siguiente instrucción a ejecutar, y CS el segmento).
El formato más sencillo para el salto sería JMP 03424h, lo que saltaría
a esa zona. Pero es algo complejo calcular en qué dirección
va a estar esa instrucción, con lo que utilizaremos etiquetas. He aquí
un ejemplo:
MOV AX,0CC34h
MOV CL,22h
JMP PALANTE
VUELVE: CMP BX,AX
JMP FIN
PALANTE: MOV BX,AX
JMP VUELVE
FIN: XOR CX,CX
Ahora comentaremos un poco el programa. Tras la primera instrucción,
AX vale 0CC34h, y tras la segunda, CL vale 22h. Después se realiza un salto
a la instrucción etiquetada con "PALANTE". La etiqueta ha de estar
continuada por dos puntos ':', y puede ser llamada desde cualquier lugar del
programa. También podremos hacer un MOV AX,[PALANTE], como hacíamos antes
con un MOV AX,[BX], pero asignando a AX el valor que haya en la dirección
en la que está "PALANTE".
El caso es que tras el salto a "PALANTE", se copia el valor del registro BX
en AX, y se vuelve a "VUELVE". Se realiza una comparación entre AX y BX, que
pondrá el flag de cero a 1 (recordemos la anterior lección), se saltará
a "FIN", donde tan sólo se realizará la orden Xor CX,CX cuyo resultado, por
cierto, es poner CX a cero, tenga el valor que tenga.
Volvamos con la sintaxis del JMP con algunos ejemplos de cómo utilizarlo:
JMP 100h
Salta a la dirección 100h. Un archivo .COM comienza normalmente en esa
dirección, así que es posible verlo en algunos virus.
JMP 542Ah:100h
Salta a la dirección 100h pero del segmento 542Ah.
JMP SHORT 223Ah
Salto corto a la dirección 223Ah.
JMP NEAR 55AAh
Salto cercano, es diferente al corto
JMP [100h]
Salta a la dirección contenida en 100h. Sin embargo es un error, ya que
no se especifica si es cercano, lejano, si se lee un solo byte,es decir,
esta instrucción no es válida.
JMP WORD PTR [BX]
Ahora sí vale. Salta a la dirección contenida en la palabra (dos
bytes) a la que apunta BX. O sea, si BX valiese 300h y en 300h los dos
bytes fuesen 0CC33h, el JMP saltaría a esta dirección.
JMP DWORD PTR [BX+SI+5]
Dword son 32 bits, o sea, un salto lejano. Y saltaría al contenido en
la dirección de memoria a la que apuntan la suma de BX,SI y 5.
Veamos el significado de los saltos lejanos, cercanos y cortos. El
salto corto se realiza entre el punto en el que se está y +127 o -128, o
sea, la cantidad que se puede contener en un byte con signo. A veces
es necesario indicar que se trata de salto corto, cercano o lejano.
El salto cercano se realiza contando como distancia el contenido de dos
bytes, o sea, que el rango sería desde 32767 a -32768 bytes de distancia.
Y el lejano se realiza contando como distancia el contenido de cuatro
Bytes.
Por ejemplo, es incorrecto que haya en la dirección 100h una instrucción
que diga JMP SHORT 500h, ya que la distancia no corresponde a un salto
corto. Además, el salto dependiendo de que sea cercano, corto o largo se
codifica de manera diferente en modo hexadecimal.
La instrucción JMP (Salto incondicional)
Una instrucción usada comúnmente para la transferencia de control es
la instrucción JMP (jump, salto, bifurcación). Un salto es incondicional,
ya que la operación transfiere el control bajo cualquier circunstancia.
También JMP vacía el resultado de la instrucción previamente
procesada; por lo que, un programa con muchas operaciones de salto
puede perder velocidad de procesamiento. El formato general para
JMP es:
| [etiqueta] | JMP | dirección corta,
cercana o lejana |
Una operación JMP dentro del mismo segmento puede ser corta o
cercana (o de manera técnica, lejana, si el destino es un
procedimiento con el atributo FAR). En su primer paso por un
programa fuente, el ensamblador genera la longitud de cada
instrucción. Sin embargo, una instrucción JMP puede ser de dos o tres
bytes de longitud. Una operación JMP a una etiqueta dentro de -128 a
+ 127 bytes es un salto corto.
El ensamblador genera un byte para la operación (EB) y un byte para
el operando. El operando actúa como un valor de desplazamiento que
la computadora suma al registro IP cuando se ejecuta el programa. El
ensamblador ya puede haber encontrado el operando designado (un
salto hacia atrás) dentro de -128 bytes, como en:
A50:
...
JMP A50
En este caso, el ensamblador genera una instrucción de maquina de
dos bytes. Una JMP que excede -128 a 127 bytes se convierte en un
salto cercano, para que el ensamblador genere un código de maquina
diferente (E9) y un operando de dos bytes (procesadores 8088/8086)
o un operando de cuatro bytes (procesadores 80386 y posteriores). En
un salto hacia adelante, el ensamblador aun no ha encontrado el
operando designado:
JMP A90
...
A90:
Ya que algunas versiones del ensamblador no saben en este punto si
el salto es corto o cercano, generan de forma automática una
instrucción de tres bytes.
TITLE
Page 60,132
P08JUMP (COM) Uso de JMP para iterar
.MODEL SMALL
.CODE
MAIN
ORG
PROC
MOV
MOV
MOV
100H
NEAR
AX,01
BX,01
CX,01
ADD
ADD
SHL
JMP
ENDP
END
AX, 01
BX, AX
CX, 1
A20
;Iniciación de AX,
;BX y
;CX a 01
A20:
MAIN
;Sumar 01 a AX
;Sumar AX a BX
;Multiplicar por dos a CX
;Saltar a la etiqueta A20
MAIN
La instrucción LOOP
La instrucción LOOP, requiere un valor inicial en el registro CX. En
cada iteración, LOOP de forma automática disminuye 1 de CX. Si el
valor en el CX es cero, el control pasa a la instrucción que sigue; si el
valor en el CX no es cero, el control pasa a la dirección del operando.
La distancia debe ser un salto corto, desde -128 hasta +127 bytes.
Para una operación que exceda este limite, el ensamblador envía un
mensaje como "salto relativo fuera de rango". El formato general de la
instrucción LOOP es:
| [etiqueta:] | LOOP |
dirección corta |
El siguiente programa muestra el funcionamiento de la instrucción
LOOP.
TITLE
Page 60,132
P08LOOP (COM) Ilustración de LOOP
.MODEL SMALL
.CODE
ORG
100H
MAIN
PROC
MOV
MOV
MOV
MOV
NEAR
AX,01
BX,01
CX,01
CX,10
ADD
ADD
SHL
LOOP
MOV
ENDP
END
AX, 01
BX, AX
DX, 1
A20
AX, 4C00H
A20:
MAIN
;Iniciación de AX,
;BX y
;CX a 01
;Iniciar
;Número de iteraciones
;Sumar 01 a AX
;Sumar AX a BX
;Multiplicar por dos a DX
;Iterar si es diferente de cero
;Salida a DOS
MAIN
Existen dos variaciones de la instrucción LOOP, ambas también
decrementan el CX en 1. LOOPE/LOOPZ (repite el ciclo mientras sea
igual o repite el ciclo mientras sea cero) continua el ciclo mientras que
el valor en el CX es cero o la condición de cero esta establecida.
LOOPNE/LOOPNZ (repite el ciclo mientras no sea igual o repite el
ciclo mientras sea cero) continua el ciclo mientras el valor en el CX no
es cero o la condición de cero no esta establecida.
2.8.2 Condicional.
SALTOS CONDICIONALES
¿Recuerdan el IF-THEN-ELSE, o el FOR, o el WHILE-DO ?
Bien, pues aquí está lo que suple a estas instrucciones en lenguaje
Ensamblador. Se basan completamente en los flags, pero están simplificados.
Los saltos podrían resumirse en un modo "Basic" de la manera IF-THEN-GOTO
de forma que cuando se cumple una condición se salta a un sitio
determinado.
He aquí los tipos de saltos condicionales (las letras en mayúsculas son
las instrucciones):
JO: Jump if overflow. Salta si el flag de desbordamiento está a uno
JNO: Jump if not overflow. Salta si el flag de desbordamiento está a
cero.
JC, JNAE, JB: Los tres sirven para lo mismo. Significan: Jump if Carry,
Jump if Not Above or Equal y Jump if Below. Saltan por lo tanto si al
haber una comparación el flag de acarreo se pone a 1; es entonces
equivalente a < en una operación sin signo. Vamos, que se compara así:
CMP 13h,18h, saltará, ya que 13h es menor que 18h. También se suelen usar
para detectar si hubo fallo en la operación, ya que muchas interrupciones
al acabar en fallo encienden el carry flag.
JNC, JAE, JNB: Otros tres que valen exactamente para lo mismo. Jump if
not Carry, Jump if Above or Equal y Jump if Not Below. Saltan por tanto si
al haber una comparación el flag de acarreo vale 0, o sea, es equivalente
al operador >=. En la comparación CMP 0,0 o CMP 13h,12h saltará, ya que el
segundo operando es MAYOR O IGUAL que el primero.
JZ o JE: Jump if Zero o Jump if Equal. Salta si el flag de cero está a
1, o sea, si las dos instrucciones comparadas son iguales. Saltaría en el
caso CMP 0,0
JNZ o JNE: Jump if Not Zero o Jump if Not Equal. Salta si el flag de cero
est a 0, o sea, si las dos instrucciones comparadas no son iguales.
JBE o JNA: Jump if Below or Equal o Jump if Not Above. Saltaría si en
resultado de la comparación el primer miembro es menor o igual que el
segundo ( <= )
JA o JNBE: Jump if Above o Jump if Not Below of Equal. Justo lo contrario
que la anterior, salta si en el resultado de la comparación el primer
miembro es mayor al segundo.
JS: Jump if Sign. Salta si el flag de signo está a uno.
JNS: Jump if Not Sign. Salta si el flag de signo está a cero.
JP, JPE: Jump if Parity o Jump if Parity Even. Salta si el flag de
paridad está a uno.
JNP, JPO: Jump if Not Parity, Jump if Parity Odd. Salta si el flag de
paridad está a cero.
JL, JNGE: Jump if Less, Jump if Not Greater of Equal. Salta si en el
resultado de la comparación, el primer número es inferior al segundo, pero
con números con signo.
JGE, JNL: Jump if Greater or Equal, Jump if Not Less. Salta si en el
resultado de la comparación, el primer número es mayor o igual que el
segundo, pero con números con signo.
JLE, JNG: Jump if Lower or Equal, Jump if Not Greater. Salta si en el
resultado de la comparación, el primer número es menor o igual que el
segundo, pero con números con signo.
JG, JNLE: Jump if Greater, Jump if Not Lower or Equal. Salta si en el
resultado de la comparación, el primer número es mayor que el segundo, para
números con signo.
Veamos algunos ejemplos de los más utilizados:
MOV AX,1111h
MOV BX,1112h
CMP AX,BX ; AX es menor que BX
JB tirapalante ; Saltar a tirapalante
HLT ; Esta orden bloquea el ordenador, halt
tirapalante: DEC BX ; Ahora BX valdr 1111h
CMP AX,BX ; Ahora valen igual
JNE Acaba ; No saltará, ya que son iguales
JE Continua ; Esta vez si
Continua: DEC BX ; Ahora BX vale 1110h
CMP AX,BX
JE Acaba ; No son iguales, por tanto no saltará
JB Acaba ; No es menor, tampoco salta
JG Acaba ; Es mayor, ahora SI saltará
Acaba: XOR AX,AX
XOR BX,BX ; AX y BX valen ahora cero.
Espero que con esto haya aclarado un poco la utilidad de los saltos.
Evidentemente, ahora al escribir sabemos cuando uno es menor o mayor, pero
a veces mediante interrupciones sacaremos valores que no conoceremos al ir
a programar, o quizá lo hagamos de la memoria, y querremos comprobar si
son iguales, etcétera.
Por cierto, que en los saltos condicionales se puede hacer como en los
incondicionales, o sea, formatos como:
JE 0022h
JNE 0030h
JNO AL
Sin embargo, estamos limitados a saltos cortos, o sea, de rango a 127
bytes hacia delante o 128 hacia atrás, no pudiendo superar esta distancia.
INSTRUCCIONES DE SALTO CONDICIONAL
El ensamblador permite usar una variedad de instrucciones de salto
condicional que transfieren el control dependiendo de las
configuraciones en el registro de banderas. Por ejemplo, puede
comparar dos campos y después saltar de acuerdo con los valores de
las banderas que la comparación establece. El formato general para el
salto condicional es:
| [etiqueta:] | Jnnn |
dirección corta |
Como ya se explico la instrucción LOOP disminuye el registro CX; si
es diferente de cero, transfiere el control a la dirección del operando.
podría reemplazar el enunciado LOOP A20 de la figura anterior con
dos enunciados - uno que decremente el CX y otro que realice un
salto condicional:
DEC CX ;Equivalente a LOOP
JNZ A20
...
DEC y JNZ realizan exactamente lo que hace LOOP. DEC
decrementa en 1 CX y pone a 1 o a 0 la bandera de cero (ZF) en el
registro de banderas. Después JNZ prueba la configuración de la
bandera de cero; si el CX es diferente de cero, el control pasa a A20, y
si el CX es cero el control pasa a la siguiente instrucción hacia abajo
Datos con signo y sin signo
Distinguir el propósito de los saltos condicionales debe clarificar su
uso. El tipo de datos (sin signo o con signo) sobre los que se realizan
las comparaciones o la aritmética puede determinar cual es la
instrucción a utilizar. Un dato sin signo trata todos los bits como bits de
datos; ejemplos típicos son las cadenas de caracteres, tal como
nombres o direcciones, y valores numéricos tal como números de
cliente. Un dato con signo trata el bit de mas a la izquierda como un
signo, en donde 0 es positivo y 1 es negativo.
En el ejemplo siguiente, el AX contiene 11000110 y el BX contiene
00010110. La siguiente instrucción
CMP AX, BX
compara el contenido de AX con el contenido del BX. Para datos sin
signo, el valor AX es mayor; sin embargo, para datos con signo el
valor AX es menor a causa del signo negativo.
Saltos con base en datos sin signo
Las instrucciones siguientes de salto condicional se aplican a datos sin
signo:
Cada una de estas pruebas las puede expresar en uno de dos códigos
simbólicos de operación.
Saltos con base en datos con signo
Las instrucciones siguientes de salto condicional se aplican a datos
con signo:
Pruebas aritméticas especiales
Las siguientes instrucciones de salto condicional tienen usos
especiales:
No espere memorizar todas estas instrucciones; sin embargo, como
recordatorio note que un salto para datos sin signo es igual, superior o
inferior, mientras que un salto para datos con signo es igual, mayor
que o menor. Los saltos que prueban banderas de acarreo, de
desbordamiento y de paridad tienen propósitos únicos.
2.9 Tipos de ciclos.
 Gestión de bucle
 LOOP (bucle)
Sintaxis: LOOP desplazamiento
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Decrementa el registro contador CX; si CX es cero, ejecuta la siguiente
instrucción, en caso contrario transfiere el control a la dirección resultante de sumar a IP
+ desplazamiento. El desplazamiento debe estar comprendido entre -128 y +127.
Ejemplo:
mov cx,10
bucle: .......
.......
loop bucle
Con las mismas características que la instrucción anterior:
 LOOPE/LOOPZ
Bucle si igual, si cero. Z=1 y CX<>0
 LOOPNE/LOOPNZ Bucle si no igual, si no cero. Z=0 y CX<>0
BUCLES
He aquí el equivalente al FOR-TO-NEXT en Ensamblador, se trata de la
orden LOOP. Lo que hace esta orden es comparar CX con cero; si es igual,
sigue adelante, si no lo es, vuelve al lugar que se indica en su operando
decrementando CX en uno. Por lo tanto, CX será un contador de las veces
que ha de repetirse el bucle. Veamos un ejemplo:
MOV CX,0005h
bucle: INC DX
CMP DX,0000h
JE Acaba
LOOP bucle
Acaba: ...
Veamos como funciona este programa. Se mueve a CX el valor 5h, que van
a ser las veces que se repita el bucle. Ahora, llegamos al cuerpo del bucle.
Se incrementa DX y se compara con 0, cuando es igual salta a "Acaba". Si
llega a la orden LOOP, CX se decrementará y saltará a bucle. Esto se
repetirá cinco veces. En fin, que el programa acabará en el grupo de
instrucciones de "Acaba" cuando la comparación dé un resultado positivo o
cuando el bucle se haya repetido cinco veces.
También tiene la limitación de que sólo realiza saltos cortos, así como
puede usarse como el JMP, de la forma:
LOOP 0003h
LOOP [AL]
En resumen, la orden LOOP es la equivalente a CMP CX,0/JNZ par metro,
donde par metro es el operando de LOOP.
2.10 Operadores Lógicos.
Operaciones lógicas y aritméticas
Las instrucciones de las operaciones lógicas son: AND, not, or y xor, éstas trabajan
sobre los bits de sus operandos.
Para verificar el resultado de operaciones recurrimos a las instrucciones cmp y test.
Las instrucciones utilizadas para las operaciones algebraicas son: para sumar add, para
restar sub, para multiplicar mul y para dividir div.
Casi todas las instrucciones de comparación están basadas en la información contenida
en el registro de banderas. Normalmente las banderas de este registro que pueden ser
directamente manipuladas por el programador son la bandera de dirección de datos DF,
usada para definir las operaciones sobre cadenas. Otra que tambien puede ser
manipulada es la bandera IF por medio de las instrucciones sti y cli, para activar y
desactivar respectivamente las interrupciones.
http://usuarios.lycos.es/patricio/ensam/ensam2.htm
 INSTRUCCIONES DE OPERACIONES LÓGICAS A NIVEL DE BIT.
 AND (y lógico)
Sintaxis: AND destino, origen
Indicadores:
OF
0
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
0
Realiza una operación de Y lógico entre el operando origen y destino
quedando el resultado en el destino. Son válidos operandos byte o palabra, pero ambos
del mismo tipo.
Ejemplos:
and
and
ax,bx
bl,byte ptr es:[si+10h]
 NOT (no lógico)
Sintaxis: NOT destino
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Realiza el complemento a uno del operando destino, invirtiendo cada uno de
sus bits. Los indicadores no resultan afectados.
Ejemplo:
not
ax
 OR (O lógico)
Sintaxis: OR destino, origen
Indicadores:
OF
0
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
0
Realiza una operación O lógico a nivel de bits entre los dos operandos,
almacenándose después el resultado en el operando destino.
Ejemplo:
or
ax,bx
 TEST (comparación lógica)
Sintaxis: TEST destino, origen
Indicadores:
OF
0
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
0
Realiza una operación Y lógica entre los dos operandos pero sin almacenar el
resultado. Los indicadores son afectados con la operación.
Ejemplo:
test
al,bh
 XOR (O exclusivo)
Sintaxis: XOR destino, origen
Indicadores:
OF
0
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
0
Operación OR exclusivo a nivel de bits entre los operandos origen y destino
almacenándose el resultado en este último.
Ejemplo:
xor
di,ax
http://meltingpot.fortunecity.com/uruguay/978/libro/04.html
Instrucciones lógicas y de manipulación de bits.
Las instrucciones lógicas ejecutan operaciones binarias sobre series de bits almacenadas
en registros. son útiles para manipular bits individuales o un grupo de bits que
represente información en código binario. Las instrucciones lógicas consideran en
forma separada cada bit del operando y la tratan como una variable booleana. Mediante
una aplicación adecuada de las instrucciones lógicas, es posible cambiar los valores de
bits, emplear un es que un grupo de bits o insertar nuevos valores de bits en los
operandos almacenados en registros o palabras de memoria.
Algunas instrucciones lógicas y de manipulación de bits típicas se listan en la tabla 8-8.
La instrucción de borrar hace que el operando especificado se sustituya con 0. La
instrucción complementar produce el complemento a 1 al invertir todos los bits del
operando. Las instrucciones AND, OR y XOR producen las operaciones lógicas
correspondientes sobre los bits individuales de los operandos. Aunque realizan
operaciones booleanas, deben considerarse que las instrucciones ejecutan operaciones
de manipulación de bits cuando se usan en instrucciones de computadora. Existen tres
operaciones de manipulación de bits posibles: un bit seleccionado puede borrarse a 0,
activarse en 1, o puede complementarse. Por lo general, se aplican las tres instrucciones
lógicas para hacer sólo eso.
La instrucción AND se utiliza para borrar un bit o un grupo seleccionado de bits de un
operando. Para cualquier variable booleana x, las relaciones xb0 = 0 y xb1 = x dictan
que una variable binaria ala que se le haya aplicado un AND con un 0 produce un 0;
pero la variable no cambia de valor cuando se le aplica un AND con un 1. Por lo tanto,
la instrucción AND puede utilizarse para borrar bits de un operando en forma selectiva
al aplicar AND al operando con otro operando que tiene 0 en las posiciones de bit que
deben borrarse. La instrucción AND también se llama máscara, y aritmética porque
enmascara o inserta 0 en una parte seleccionada de un operando.
La instrucción OR se utiliza para activar un bit o un grupo seleccionado de bits de un
operando. Para cualquier variable booleana x, las relaciones x + 1 = 1 y x + 0 = x dictan
que una variable binaria ala que se le aplica OR con un 1 produce un 1; pero la variable
no cambia cuando se .le aplica OR con un 0. Por lo tanto, la instrucción OR puede
utilizarse para activar bits de un operando en forma selectiva, al aplicar OR con otro
operando Con dígitos 1 en las posiciones de bits que deben activarse en 1.
TABLA 8-8 Instrucciones lógicas y de manipulación de bits típicas
NOMBRE
MNEMONICO
Borrar
CLR
complementar
COM
Aplicar la función AND
AND
Aplicar la función OR
OR
Aplicar la función OR
exclusiva
XOR
Desactivar acarreo
CLRC
Activar acarreo
SETC
Complementar acarreo
COMC
Habilitar interrupción
EI
Deshabilitar interrupción
DI
De igual forma, la instrucción XOR se utiliza para complementar bits de un operando en
forma selectiva. Esto se debe a la relación boolena x(+) 1= x' y x (+) 0 = x. Por lo tanto,
una variable binaria se complementa cuando se le aplica XOR con un 1, pero no cambia
en valor cuando se le aplica XOR con un 0. En la sección 4-5 se muestran ejemplos
numéricos de las tres operaciones lógicas.
En la tabla 8-8 se incluyen algunas otras instrucciones de manipulación de bits. Los bits
individuales (como los de un acarreo) pueden borrarse, activarse o complementarse con
las instrucciones apropiadas. Otro ejemplo es un flip-flop que controla la opción de
interrupción y se habilita o deshabilita mediante instrucciones de manipulación de bits.
http://members.fortunecity.es/roy8/cpu.htm
2.11 Desplazamiento.
Ver archivo: algo_desplazamientos.pdf
 INSTRUCCIONES DE ROTACIÓN Y DESPLAZAMIENTO.
 RCL (rotación a la izquierda con acarreo)
Sintaxis: RCL destino, contador
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
x
Rotar a la izquierda los bits del operando destino junto con el indicador de
acarreo CF el número de bits especificado en el segundo operando. Si el número de bits
a desplazar es 1, se puede especificar directamente, en caso contrario el valor debe
cargarse en CL y especificar CL como segundo operando. No es conveniente que CL
sea mayor de 7, en bytes; ó 15, en palabras.
Ejemplos:
rcl
rcl
rcl
ax,1
al,cl
di,1
 RCR (rotación a la derecha con acarreo)
Sintaxis: RCR destino, contador
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
x
Rotar a la derecha los bits del operando destino junto con el indicador de
acarreo CF el número de bits especificado en el segundo operando. Si el número de bits
es 1 se puede especificar directamente; en caso contrario su valor debe cargarse en CL y
especificar CL como segundo operando:
Ejemplos:
rcr
rcr
bx,cl
bx,1
 ROL (rotación a la izquierda)
Sintaxis: ROL destino, contador
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
x
Rota a la izquierda los bits del operando destino el número de bits especificado
en el segundo operando, que puede ser 1 ó CL previamente cargado con el valor del
número de veces.
Ejemplos:
rol
rol
dx,cl
ah,1
 ROR (rotación a la derecha)
Sintaxis: ROR destino, contador
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
x
Rota a la derecha los bits del operando destino el número de bits especificado
en el segundo operando. Si el número de bits es 1 se puede poner directamente, en caso
contrario debe ponerse a través de CL.
Ejemplos:
ror
ror
cl,1
ax,cl
 SAL/SHL (desplazamiento aritmético a la izquierda)
Sintaxis: SAL/SHL destino, contador
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
x
Desplaza a la izquierda los bits del operando el número de bits especificado en
el segundo operando que debe ser CL si es mayor que 1 los bits desplazados.
 SAR (desplazamiento aritmético a la derecha)
Sintaxis: SAR destino, contador
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
x
Desplaza a la derecha los bits del operando destino el número de bits
especificado en el segundo operando. Los bits de la izquierda se rellenan con el bit de
signo del primer operando. Si el número de bits a desplazar es 1 se puede especificar
directamente, si es mayor se especifica a través de CL.
Ejemplos:
sar
sar
 SHR (desplazamiento lógico a la derecha)
Sintaxis: SHR destino, contador
ax,cl
bp,1
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
?
PF
x
CF
x
Desplaza a la derecha los bits del operando destino el número de los bits
especificados en el segundo operando. Los bits de la izquierda se llena con cero. Si el
número de bits a desplazar es 1 se puede especificar directamente en el caso en que no
ocurra se pone el valor en CL:
Ejemplos:
shr
shr
ax,cl
cl,1
http://meltingpot.fortunecity.com/uruguay/978/libro/04.html
2.11.1 Lineal.
Instrucciones de corrimiento
Las instrucciones para recorrer el contenido de un operando son muy útiles y se ofrecen
con frecuencia en diversas variaciones. Los corrimientos son operaciones en las cuales
los bits de una palabra se recorren a la izquierda o derecha. El bit que se recorre al
extremo de la palabra determina el tipo de corrimiento que utiliza. Las instrucciones de
corrimiento pueden especificar corrimientos lógicos, aritméticos u operaciones de tipo
rotatorio. En cualquier caso, el corrimiento puede ser a la derecha o a la izquierda. ,
La tabla 8-9 lista cuatro tipos de instrucciones de corrimiento. El corrimiento lógico
inserta un 0 al de la posición final de bit. La posición final es el bit al extremo izquierdo
para el corrimiento a la derecha y el bit al extremo derecho para el corrimiento a la
izquierda. Por lo general, los corrimientos aritméticos se apegan a las reglas para los
números de complemento a 2 con signo. Estas reglas se proporcionan en la sección 4-6.
La instrucción aritmética de corrimiento a la derecha debe preservar el bit de signo en la
posición al extremo izquierdo. El bit de signo se desplaza ala derecha.
TABLA 8-9 Instrucciones de corrimiento típicas
NOMBRE
MNEMONICO
Corrimiento a la derecha lógico
SHR
Corrimiento a la izquierda lógico
SHL
Corrimiento a la derecha aritmético
SHRA
Corrimiento a la izquierda aritmético
SHLA
Rotar a la derecha
ROR
Rotar a la izquierda
ROL
Rotar a la derecha mediante acarreo
RORC
Rotar a la izquierda mediante acarreo
ROLC
Junto con el resto del número, pero el bit de signo no cambia. Esta es una operación de
corrimiento a la derecha en la que el bit final permanece igual. La instrucción de
corrimiento aritmético a la izquierda inserta 0 en la posición fina.! y es idéntica a la
instrucción lógica de corrimiento a la izquierda. Por esta razón muchas computadoras
no proporcionan una instrucción distinta de corrimiento aritmético a la izquierda cuando
ya está disponible la instrucción de corrimiento lógico a la izquierda.
Las instrucciones de rotación producen un corrimiento circular. Los bits recorridos en
un extremo de la palabra no se pierden en un desplazamiento lógico, pero se hacen
circular hasta el otro extremo. La instrucción de rotación a través del bit de acarreo trata
al bit de acarreo como una extensión del registro cuya palabra se está rotando. Por lo
tanto una instrucción de rotación ala izquierda a través del acarreo transfiere el. bit de
acarreo a la posición de bit a la extrema derecha del registro, transfiere la posición de la
extrema izquierda al acarreo y, al mismo tiempo, recorre todo el registro a la izquierda.
Algunas computadoras tienen un formato de campo múltiple para las instrucciones de
corrimiento. Un campo contiene el código de operación y los otros especifican el tipo de
corrimiento y la cantidad de veces que se va a recorrer un operando. Un formato de
código de instrucción posible de una instrucción de desplazamiento puede incluir cinco
campos de la manera siguiente.
OP REG TYPE RL COUNT
Aquí OP es el campo de código de operación; REG es una dirección de registro que
especifica la posición del operando; TYPE es un campo de 2 bits que especifica los
cuatro diferentes tipos de corrimientos; LR es un campo de 1 bit que especifica un
corrimiento a la derecha o ala izquierda y COUNT es un campo de k bits que especifica
hasta 2k -1 corrimientos. Con tal formato es posible especificar el tipo de corrimiento, la
dirección y la cantidad de corrimientos, todo en una sola instrucción.
CORRIMIENTO DE BITS.
Las instrucciones de corrimiento, que son parte de la capacidad lógica
de la computadora, pueden realizar las siguientes acciones:
1. Hacer referencia a un registro o dirección de memoria.
2. Recorre bits a la izquierda o a la derecha.
3. Recorre hasta 8 bits en un byte, 16 bits en una palabra y 32 bits en
una palabra doble.
4. Corrimiento lógico (sin signo) o aritmético (con signo).
El segundo operando contiene el valor del corrimiento, que es una
constante (un valor inmediato) o una referencia al registro CL. Para los
procesadores 8088/8086, la constante inmediata solo puede ser 1; un
valor de corrimiento mayor que 1 debe estar contenido en el registro
CL. Procesadores posteriores permiten constantes de corrimiento
inmediato hasta 31.
El formato general para el corrimiento es
| [etiqueta:] | Corrim. | {registro/memoria},
{CL/inmediato} |
Corrimiento de bits hacia la derecha.
Los corrimientos hacia la derecha (SHR y SAR) mueven los bits hacia
la derecha en el registro designado. El bit recorrido fuera del registro
mete la bandera de acarreo. Las instrucciones de corrimiento a la
derecha estipulan datos lógicos (sin signo) o aritméticos (con signo):
Las siguientes instrucciones relacionadas ilustran SHR y datos con
signo:
INSTRUCCION
MOV
MOV
SHR
SHR
la derecha
SHR
posteriores
CL, 03
AL, 10110111B
AL, 01
AL, CL
AX, 03
AL
COMENTARIO
; 10110111
; 11011011 Un corrimiento a la derecha
; 00001011 Tres corrimientos adicionales a
; Válido para 80186 y procesadores
El primer SHR desplaza el contenido de AL un bit hacia la derecha. El
bit de mas a la derecha es enviado a la bandera de acarreo, y el bit de
mas a la izquierda se llena con un cero. El segundo SHR desplaza
tres bits mas al AL. La bandera de acarreo contiene de manera
sucesiva 1, 1 y 0; además, tres bits 0 son colocados a la izquierda del
AL.
SAR se difiere de SHR en un punto importante: SAR utiliza el bit de
signo para llenar el bit vacante de mas a la izquierda. De esta manera,
los valores positivos y negativos retienen sus signos. Las siguientes
instrucciones relacionadas ilustran SAR y datos con signo en los que
el signo es un bit 1:
INSTRUCCION
MOV
MOV
SHR
SHR
derecha
SHR
CL, 03
AL, 10110111B
AL, 01
AL, CL
AX, 03
AL
COMENTARIO
;; 10110111
; 11011011 Un corrimiento a la derecha
; 00001011 Tres corrimientos adicionales a la
; Válido para 80186 y procesadores posteriores
En especial, los corrimientos a la derecha son útiles para (dividir entre
2) obtener mitades de valores y son mucho mas rápidas que utilizar
una operación de división.
Al terminar una operación de corrimiento, puede utilizar la instrucción
JC (Salta si hay acarreo) para examinar el bit desplazado a la bandera
de acarreo.
Corrimiento de bits a la izquierda.
Los corrimientos hacia la izquierda (SHL y SAL) mueven los bits a la
izquierda, en el registro designado. SHL y SAL son idénticos en su
operación. El bit desplazado fuera del registro ingresa a la bandera de
acarreo. Las instrucciones de corrimiento hacia la izquierda estipulan
datos lógicos (sin signo) y aritméticos (con signo):
SHL: Desplazamiento lógico a la izquierda
aritmético a la izquierda
SAL: Desplazamiento
Las siguientes instrucciones relacionadas ilustran SHL para datos sin
signo:
INSTRUCCION
MOV CL, 03
MOV AL, 10110111B
SHR AL, 01
SHR AL, CL
SHR AX, 03
posteriores
AL
COMENTARIO
; 10110111
; 01101110 Un corrimiento a la izquierda
; 01110000 Tres corrimientos mas
; Válido para 80186 y procesadores
El primer SHL desplaza el contenido de AL un bit hacia la izquierda. El
bit de mas a la izquierda ahora se encuentra en la bandera de acarreo,
y el ultimo bit de la derecha del AL se llena con cero. El segundo SHL
desplaza tres bits mas a el AL. La bandera de acarreo contiene en
forma sucesiva 0, 1 y 1, y se llena con tres ceros a la derecha del AL.
Los corrimientos a la izquierda llenan con cero el bit de mas a la
derecha. Como resultado de esto, SHL y SAL don idénticos. Los
corrimientos a la izquierda en especial son útiles para duplicar valores
y son mucho mas rápidos que usar una operación de multiplicación.
Al terminar una operación de corrimiento, puede utilizar la instrucción
JC (Salta si hay acarreo) para examinar el bit que ingreso a la bandera
de acarreo.
http://www.itlp.edu.mx/publica/tutoriales/ensamblador/
2.11.2 Circular.
3
ROTACION DE BITS (Desplazamiento circular)
Las instrucciones de rotación, que son parte de la capacidad lógica de
la computadora, pueden realizar las siguientes acciones:
1. Hacer referencia a un byte o a una palabra.
2. Hacer referencia a un registro o a memoria.
3. Realizar rotación a la derecha o a la izquierda. El bit que es
desplazado fuera llena
el espacio vacante en la memoria o registro y también se copia en la
bandera de acarreo.
4. Realizar rotación hasta 8 bits en un byte, 16 bits en una palabra y
32 bits en una palabra doble.
5. Realizar rotación lógica (sin signo) o aritmética (con signo).
El segundo operando contiene un valor de rotación, el cual es una
constante (un valor inmediato) o una referencia al registro CL. Para los
procesadores 8088/8086, la constante inmediata solo puede ser 1; un
valor de rotación mayor que 1 debe estar contenido en el registro CL.
Procesadores posteriores permiten constantes inmediatas hasta el 31.
El formato general para la rotación es:
| [etiqueta:] | Rotación | {registro/memoria},
{CL/inmediato} |
Rotación a la derecha de bits
Las rotaciones a la derecha (ROR y RCR) desplazan a la derecha los
bits en el registro designado. Las instrucciones de rotación a la
derecha estipulan datos lógicos (sin signo) o aritméticos (con signo):
Las siguientes instrucciones relacionadas ilustran ROR:
INSTRUCCION
BH
COMENTARIO
MOV CL, 03
MOV BH, 10110111B
SHR BH, 01
SHR BH, CL
SHR BX, 03
posteriores
; 10110111
; 11011011 Una rotación a la derecha
; 00001011 Tres rotaciones a la derecha
; Válido para 80186 y procesadores
El primer ROR desplaza el bit de mas a la derecha del BH a la
posición vacante de mas a la izquierda. La segunda y tercera
operaciones ROR realizan la rotación de los tres bits de mas a la
derecha.
RCR provoca que la bandera de acarreo participe en la rotación. Cada
bit que se desplaza fuera de la derecha se mueve al CF y el bit del CF
se mueve a la posición vacante de la izquierda.
Rotación a la izquierda de bits
Las rotaciones a la izquierda (ROL y RCL) desplazan a la izquierda los
bits del registro designado. Las instrucciones de rotación a la izquierda
estipulan datos lógicos (sin signo) y aritméticos (con signo):
Las siguientes instrucciones relacionadas ilustran ROL:
INSTRUCCION
MOV CL, 03
MOV BL, 10110111B
SHR BL, 01
SHR BL, CL
SHR BX, 03
posteriores
BL
COMENTARIO
; 10110111
; 11011011 Una rotación a la izquierda
; 00001011 Tres rotaciones a la izquierda
; Válido para 80186 y procesadores
El primer ROL desplaza el bit de mas a la izquierda del BL a la
posición vacante de mas a la derecha. La segunda y tercera
operaciones ROL realizan la rotación de los tres bits de mas a la
izquierda.
De manera similar a RCR, RCL también provoca que la bandera de
acarreo participe en la rotación. Cada bit que se desplaza fuera por la
izquierda se mueve al CF, y el bit del CF se mueve a la posición
vacante de la derecha.
Puede usar la instrucción JC (salta si hay acarreo) para comprobar el
bit rotado hacia la CF en el extremo de una operación de rotación.
http://www.itlp.edu.mx/publica/tutoriales/ensamblador/tem6_4_.htm
3.1 Procesos de control.
3.1.1 Banderas.
FLAGS
La explicación de los "flags" está relacionada con los saltos condicionales.
Los que hayáis visto un mínimo de otros lenguajes recordaréis las sentencias
FOR y NEXT (en Basic), o el IF/THEN/ELSE también en estilo Basic pero que
también se encuentran en otros lenguajes. Pues bien, los flags y las instrucciones
condicionales va a ser lo que os encontréis en este capítulo.
Veamos el registro de flags.
A las flags, "banderas", las agrupa un solo registro de 16 bits, aunque
éste no esté utilizado por completo, ya que cada flag ocupa un solo bit.
¿Qué son los flags?
Se trata de varios bits, que, como siempre, pueden valer uno o cero, y
dependiendo de su valor indican varias cosas. El registro de flags es como
sigue:
³±³±³±³±³O³D³I³T³S³Z³±³A³±³P³±³C³
O: Overflow D: Dirección I: Interrupciones rehabilitadas
T: Trampa S: Signo Z: Cero
A: Acarreo auxiliar P: Paridad C: Acarreo ±: No utilizado
Cada cuadro representa un bit como es fácil adivinar. También está claro que
cada bit que se utiliza tiene un nombre, y como se verá, también
una utilidad. Aquí explico el significado de los
más importantes:
EL FLAG DE ACARREO
Hay veces en la operaciones en las que el número se desborda, o sea, no
cabe en el registro o en la posición de memoria. Imaginemos que tenemos en
AX el número 0FFFFh y le sumamos 0CCCCh. Como es lógico, el resultado no nos
cabrá en AX. Al realizar esta suma, tenemos que tener en cuenta que el
siguiente número a 0FFFFh es 0000h, con lo que podremos ver el resultado.
Igual pasará si a 0000h le restamos, por ejemplo, 1 (el resultado será
0FFFFh). Pero de alguna manera nos tenemos que DAR CUENTA de que esto ha
sucedido.
Cuando se opera y hay acarreo en el último bit sobre el que se ha
operado, el flag de acarreo se pone a uno, es decir, cuando ese número se ha
desbordado. Hay que recordar también que las instrucciones INC y DEC no
afectan a este flag. Veamos los efectos de estas operaciones:
MOV AX,0FFFFh
INC AX ; AX vale ahora 0, el flag de acarreo también
DEC AX ; AX vale 0FFFFh, y el flag sigue inalterado
ADD AX,1 ; AX vale 0, y el flag de acarreo está a 1
MOV BX,0000h
ADD BX,50h ; El flag de acarreo se pone a 0, no ha habido
;acarreo en esta operación
SUB AX,1 ; Ahora AX vale otra vez 0FFFFh, y el flag de acarreo
;se pone de nuevo a uno.
En resumen, se activa cuando tras una operación hay un paso del valor
máximo al mínimo o viceversa.
Este flag nos va a ser también útil al comprobar errores, etc. Por
ejemplo, si buscamos el primer archivo del directorio y no hay ninguno,
este flag se activará, con lo que podremos usar los saltos condicionales,
pero esto ya se explicará más adelante.
EL FLAG DE SIGNO
A veces interesa conocer cuándo un número con signo es negativo o positivo.
Evidentemente, esto sólo tiene efecto cuando estamos tratando
con números enteros con signo, en complemento a dos. Indica cuando tras una
operación aritmética (ADD, SUB, INC, DEC o NEG o lógica (AND, OR o XOR)
el resultado es un número en complemento a dos. En realidad, es la copia del
bit de mayor peso del byte, el que indica cuándo el número es negativo.
Por lo tanto, cuando vale 1 es que el número es negativo y si vale 0 es
que es positivo.
EL FLAG DE DESBORDAMIENTO ("Overflow")
Se trata de un flag bastante parecido al de acarreo, pero que actúa con
números en complemento a dos y se activa cuando se pasa del mayor número
positivo (127 en un solo byte) al menor negativo (-128 en tamaño de un
byte).
Este flag, al contrario que el de acarreo, SI es afectado por las
instrucciones de decremento e incremento.
EL FLAG DE CERO
Es de los más sencillos de comprender. Simplemente se activa cuando el
resultado de una operación aritmética o lógica es cero. Es evidente la gran utilidad del
flag.
Tenemos, por ejemplo, dos registros, AX y CX, que queremos comparar para saber si
son iguales.
Para saberlo, no tendríamos más que restar uno del otro, y si el resultado
es cero (o sea, si el flag de cero se pone en uno), podremos hacer un
salto condicional.
O sea, de un
SUB CX,AX
Si son iguales, el flag de cero se pondrá a uno.
EL FLAG DE PARIDAD
Se utiliza especialmente en la transmisión de datos para la comprobación
de errores, ya que comprueba si el resultado de la última operación
aritmética o lógica realizada tiene un número par o impar de bits puestos
a uno. Se pondrá a uno cuando haya un número par de bits, y a cero cuando
sea impar.
RESTO DE FLAGS
No describiré más flags detalladamente, ya que su importancia es casi
nula; por ejemplo está el flag de interrupción, que, cuando está activado,
evita la posibilidad de interrupciones en secciones críticas de código, o
el de trampa, que cuando está activado provoca una INT 1h cada vez que se
ejecuta otra instrucción, pero creo que su interés es escaso, al menos por
el momento.
3.1.2 Cadenas.
INSTRUCCIONES DE CADENA
Son un subconjunto de instrucciones muy útiles para diversas funciones:
inicializar zonas de memoria, copiar datos de una zona a otra, encontrar
valores determinados o comparar cadenas, etc., etc.
Su comportamiento depende del flag de dirección del que hablábamos unas
lecciones más atrás, y que se puede cambiar directamente con estas dos
instrucciones:
STD: SeT Direction flag, lo pone a uno.
CLD: CLear Direction flag, lo pone a cero.
Las instrucciones que vamos a usar como de cadena siempre tienen una S
de String al final, y casi siempre además una B o una W indicando Byte o
Word (el tamaño).
Y estas son:
LODSB/LODSW
Lee un byte/palabra en la dirección de memoria dada por DS:SI y la
almacena dependiendo de su tamaño en AL o AX. Si el flag de dirección está
a cero, según sea byte o palabra, SI aumentará en 1 o 2 unidades (para
poder continuar la operación de lectura). Si está a uno el flag, se
decrementará en 1 o 2 unidades dependiendo del tamaño (byte/palabra)
STOSB/STOSW
Es el equivalente a "grabar" si lo anterior era "cargar". Almacenará el
contenido de AL o AX (como siempre, dependiendo del tamaño ) en ES:DI,
copiando según si es B o W uno o dos bytes cada vez que se ejecute.
Si el flag de dirección está a cero, DI aumentará cada vez que se
realice la orden en una o dos unidades (dependiendo del tamaño, B o W ).
Si está a uno, decrecerá.
MOVSB/MOVSW
Mueve el byte o palabra contenido en la dirección de memoria a la que
apunta DS:SI a la dirección de memoria de ES:DI.
Si el flag de dirección está a 0, con cada MOVS que realicemos SI y DI
aumentarán en una unidad (MOVSB) o dos (MOVSW). Si está a uno, se
decrementarán de igual manera.
REP
Acabo de hablar sobre él. Pues bien, si se utiliza como operando suyo
una de estas órdenes, la repetirá CX veces. Por ejemplo, si queremos
copiar la tabla de vectores de interrupción a un lugar que hemos
reservado:
cld ; A asegurarnos de que el flag de dirección está.
;a cero.
mov cx,400h
xor dx,dx ; pone dx a 0
push dx
pop ds ; No está permitido hacer xor ds,ds, por lo que
;metemos dx, que vale 0, en la pila, y sacamos
;DS valiendo 0.
xor si,si ; SI que valga 0.
push cs
pop es ; Vamos a asegurarnos de que ES valga CS, o sea,
;el segmento en el que está el programa ahora.
mov di,buffer ; DI apunta al lugar donde vamos a guardar la
;tabla.
rep movsb ; Repite ‚esto 400h veces, y cada vez que lo hace
;incrementa DI y SI.
int 20h ; Acaba la ejecución.
buffer: db 400h dup (?) ; Esto deja un espacio de 400h bytes que nos
;va a servir para almacenar la tabla de
;vectores de interrupción.
Podemos, para empezar, reducir el 400h a 200h en CX, y hacer un rep movsw,
con lo que trasladaremos de palabra en palabra las instrucciones.
 INSTRUCCIONES DE MANIPULACIÓN DE CADENAS.
 CMPS/CMPSB/CMPSW (compara cadenas)
Sintaxis:
CMPS cadena_destino, cadena_origen
CMPSB (bytes)
CMPSW (palabras)
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Compara dos cadenas restando al origen el destino. Ninguno de los operandos
se alteran, pero los indicadores resultan afectados. La cadena origen se direcciona con
registro SI sobre el segmento de datos DS y la cadena destino se direcciona con el
registro DI sobre el segmento extra ES. Los registros DI y SI se autoincrementan o
autodecrementan según el valor del indicador DF (véanse CLD y STD) en una o dos
unidades, dependiendo de si se trabaja con bytes o con palabras. Cadena origen y
cadena destino son dos operandos redundantes que sólo indican el tipo del dato (byte o
palabra) a comparar, es más cómodo colocar CMPSB o CMPSW para indicar
bytes/palabras. Si se indica un registro de segmento, éste sustituirá en la cadena origen
al DS ordinario. Ejemplo:
lea
lea
cmpsb
 LODS/LODSB/LODSW (cargar cadena)
Sintaxis:
LODS
cadena_origen
si,origen
di,destino
LODSB (bytes)
LODSW (palabras)
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Copia en AL o AX una cadena de longitud byte o palabra direccionada sobre
el segmento de datos (DS) con el registro SI. Tras la transferencia, SI se incrementa o
decrementa según el indicador DF (véanse CLD y STD) en una o dos unidades, según
se estén manejando bytes o palabras. Cadena_origen es un operando redundante que
sólo indica el tipo del dato (byte o palabra) a cargar, es más cómodo colocar LODSB o
LODSW para indicar bytes/palabras.
Ejemplo:
cld
lea
lodsb
si,origen
 MOVS/MOVSB/MOVSW (mover cadena)
Sintaxis:
MOVS cadena_destino, cadena_origen
MOVSB (bytes)
MOVSW (palabras)
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere un byte o una palabra de la cadena origen direccionada por DS:SI a
la cadena destino direccionada por ES:DI, incrementando o decrementando a
continuación los registros SI y DI según el valor de DF (véanse CLD y STD) en una o
dos unidades, dependiendo de si se trabaja con bytes o con palabras. Cadena origen y
cadena destino son dos operandos redundantes que sólo indican el tipo del dato (byte o
palabra) a comparar, es más cómodo colocar MOVSB o MOVSW para indicar
bytes/palabras. Si se indica un registro de segmento, éste sustituirá en la cadena origen
al DS ordinario.
Ejemplo:
lea
lea
movsw
si,origen
di,destino
 SCAS/SCASB/SCASW (explorar cadena)
Sintaxis:
SCAS cadena_destino
SCASB (bytes)
SCASW (palabras)
Indicadores:
OF
x
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Resta de AX o AL una cadena destino direccionada por el registro DI sobre el
segmento extra. Ninguno de los valores es alterado pero los indicadores se ven
afectados. DI se incrementa o decrementa según el valor de DF (véanse CLD y STD) en
una o dos unidades -según se esté trabajando con bytes o palabras- para apuntar al
siguiente elemento de la cadena. Cadena_destino es un operando redundante que sólo
indica el tipo del dato (byte o palabra), es más cómodo colocar SCASB o SCASW para
indicar bytes/palabras.
Ejemplo:
lea
mov
scasb
di,destino
al,50
 STOS/STOSB/STOSW (almacena cadena)
Sintaxis:
STOS cadena_destino
STOSB (bytes)
STOSW (palabras)
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere el operando origen almacenado en AX o AL, al destino
direccionado por el registro DI sobre el segmento extra. Tras la operación, DI se
incrementa o decrementa según el indicador DF (véanse CLD y STD) para apuntar al
siguiente elemento de la cadena. Cadena_destino es un operando redundante que sólo
indica el tipo del dato (byte o palabra) a cargar, es más cómodo colocar STOSB o
STOSW para indicar bytes/palabras.
Ejemplo:
lea
mov
stosw
di,destino
ax,1991
 REP/REPE/REPZ/REPNE/REPNZ (repetir)
REP
repetir operación de cadena
REPE/REPZ
repetir operación de cadena si igual/si cero
REPNE/REPNZ repetir operación de cadena si no igual (si no 0)
Estas instrucciones se pueden colocar como prefijo de otra instrucción de
manejo de cadenas, con objeto de que la misma se repita un número determinado de
veces incondicionalmente o hasta que se verifique alguna condición. El número de
veces se indica en CX. Por sentido común sólo deben utilizarse las siguientes
combinaciones:
Prefijo
Instrucciones
-----------REP
REPE/REPZ
REPNE/REPNZ
Ejemplos:
Función
------------------------------Repetir CX veces
Repetir CX veces mientras ZF=1
Repetir CX veces mientras ZF=0
-------------MOVS, STOS
CMPS, SCAS
CMPS, SCAS
1) Buscar el byte 69 entre las 200 primeras posiciones de tabla (se supone
tabla en el segmento ES):
LEA
MOV
MOV
CLD
REPNE
JE
DI,tabla
CX,200
AL,69
SCASB
encontrado
2) Rellenar de ceros 5000 bytes de una tabla colocada en datos (se supone
datos en el segmento ES):
LEA
MOV
MOV
CLD
REP
DI,datos
AX,0
CX,2500
STOSW
3) Copiar la memoria de pantalla de texto (adaptador de color) de un PC en un
buffer (se supone buffer en el segmento ES):
MOV
MOV
LEA
MOV
MOV
CLD
REP
CX,0B800h
DS,CX
DI,buffer
SI,0
CX,2000
;
;
;
;
;
;
;
MOVSW
segmento de pantalla
en DS
destino en ES:DI
copiar desde DS:0
2000 palabras
hacia adelante
copiar CX palabras
http://meltingpot.fortunecity.com/uruguay/978/libro/04.html
3.1.3 Carga.
Las primeras dos instrucciones permiten el intercambio de datos entre la memoria y el registro
del procesador.
La instrucci¶on LOAD copia un dato de la memoria al registro, mientras que la instruccion
STORE lo hace en el sentido inverso. La instrucci¶on LOADI permite cargar un operando
inmediato en el registro, es decir, un valor constante que se incluye en la instrucci¶on misma.
Por ejemplo, LOADI 5 hace que el valor 5 se copie al registro. Observe la diferencia con LOAD
5, que copia al registro el contenido de la celda cuya direcci¶on es 5.
INSTRUCCIONES DE CARGA DE REGISTROS Y DIRECCIONES.
 MOV (transferencia)
Sintaxis: MOV dest, origen.
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere datos de longitud byte o palabra del operando origen al operando
destino. Pueden ser operando origen y operando destino cualquier registro o posición de
memoria direccionada de las formas ya vistas, con la única condición de que origen y
destino tengan la misma dimensión. Existen ciertas limitaciones, como que los registros
de segmento no admiten el direccionamiento inmediato: es incorrecto MOV DS,4000h;
pero no lo es por ejemplo MOV DS,AX o MOV DS,VARIABLE. No es posible, así
mismo, utilizar CS como destino (es incorrecto hacer MOV CS,AX aunque pueda
admitirlo algún ensamblador). Al hacer MOV hacia un registro de segmento, las
interrupciones quedan inhibidas hasta después de ejecutarse la siguiente instrucción
(8086/88 de 1983 y procesadores posteriores).
Ejemplos:
mov
mov
mov
ds,ax
bx,es:[si]
si,offset dato
En el último ejemplo, no se coloca en SI el valor de la variable dato sino su
dirección de memoria o desplazamiento respecto al segmento de datos. En otras
palabras, SI es un puntero a dato pero no es dato. En el próximo capítulo se verá cómo
se declaran las variables.
 XCHG (intercambiar)
Sintaxis: XCHG destino, origen
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Intercambia el contenido de los operandos origen y destino. No pueden
utilizarse registros de segmentos como operandos.
Ejemplo:
xchg
xchg
bl,ch
mem_pal,bx
 XLAT (traducción)
Sintaxis: XLAT tabla
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Se utiliza para traducir un byte del registro AL a un byte tomado de la tabla de
traducción. Los datos se toman desde una dirección de la tabla correspondiente a BX +
AL, donde bx es un puntero a el comienzo de la tabla y AL es un índice. Indicar tabla al
lado de xlat es sólo una redundancia opcional.
Ejemplo:
mov
mov
xlat
bx,offset tabla
al,4
 LEA (carga dirección efectiva)
Sintaxis: LEA destino, origen
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Transfiere el desplazamiento del operando fuente al operando destino. Otras
instrucciones pueden a continuación utilizar el registro como desplazamiento para
acceder a los datos que constituyen el objetivo. El operando destino no puede ser un
registro de segmento. En general, esta instrucción es equivalente a MOV
destino,OFFSET fuente y de hecho los buenos ensambladores (TASM) la codifican
como MOV para economizar un byte de memoria. Sin embargo, LEA es en algunos
casos más potente que MOV al permitir indicar registros de índice y desplazamiento
para calcular el offset:
lea
dx,datos[si]
En el ejemplo de arriba, el valor depositado en DX es el offset de la etiqueta
datos más el registro SI. Esa sola instrucción es equivalente a estas dos:
mov
add
dx,offset datos
dx,si
 LDS (carga un puntero utilizando DS)
Sintaxis: LDS destino, origen
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Traslada un puntero de 32 bits (dirección completa de memoria compuesta por
segmento y desplazamiento), al destino indicado y a DS. A partir de la dirección
indicada por el operando origen, el procesador toma 4 bytes de la memoria: con los dos
primeros forma una palabra que deposita en destino y, con los otros dos, otra en DS.
Ejemplo:
punt
dd
lds
12345678h
si,punt
Como resultado de esta instrucción, en DS:SI se hace referencia a la posición
de memoria 1234h:5678h; 'dd' sirve para definir una variable larga de 4 bytes
(denominada punt en el ejemplo) y será explicado en el capítulo siguiente.
 LES (carga un puntero utilizando ES)
Sintaxis: LES destino, origen
Esta instrucción es análoga a LDS, pero utilizando ES en lugar de DS.
 LAHF (carga AH con los indicadores)
Sintaxis: LAHF
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
-
ZF
-
AF
-
PF
-
CF
-
Carga los bits 7, 6, 4, 2 y 0 del registro AH con el contenido de los indicadores
SF, ZF, AF, PF Y CF respectivamente. El contenido de los demás bits queda sin definir.
 SAHF (copia AH en los indicadores)
Sintaxis: SAHF
Indicadores:
OF
-
DF
-
IF
-
TF
-
SF
x
ZF
x
AF
x
PF
x
CF
x
Transfiere el contenido de los bits 7, 6, 4, 2 y 0 a los indicadores SF, ZF, AF,
PF y CF respectivamente.
http://ing.utalca.cl/~fmeza/cursos/cyp/tema3.pdf
1. La instrucción load (cargar) se ha usado principalmente para designar una
transferencia de memoria aun registro de programación, por lo general un
acumulador. La instrucción store (almacenar) representa una transferencia de un
registro de procesador a la memoria. La instrucción mov (mover) se ha usado en
las computadoras con registros múltiples de CPU para designar una
transferencia de un registro a otro. También se ha usado para transferencias de
datos entre registros de CPU y la memoria o entre dos palabras de memoria. La
instrucción exchange (intercambiar) cambia la información entre dos registros o
un registro y una palabra de memoria. Las instrucciones input (introducir) y
output (sacar) transfieren datos entre registros del procesador y terminales de
entrada o salida. Las instrucciones push (empujar) y pop (saltar) transfieren
datos entres registros del procesador y una pila de memoria.
Debe recordarse que las instrucciones que se listan en la tabla 8-5, al igual que
en las tablas siguientes en esta sección, con frecuencia están asociadas con
diversos modos de direccionamiento. Algunas normas del lenguaje ensamblador
modifican el símbolo mnemónico para diferenciar entre los diversos modos de
direccionamiento. Por ejemplo, el mnemónico para
TABLA 8-5 Instrucciones de transferencia de datos típica
Nombre
Mnemónico
Cargar
LD
Almacenar
ST
Mover
MOV
Intercambiar
XCH
Entrada
IN
Salida
OUT
Empujar
PUSH
Saltar
POP
TABLA 8-6 Ocho modos de direccionamiento para la introducción cargar
Modo
Convención en ensamblador
Transferencia de registros
Direccionamiento directo
LD ADR
AC = M[M[ADR]]
Direccionamiento indirecto
LD @ ADR
AC = M[M[ADR]]
Direccionamiento relativo
LD $ ADR
AC = M[PC +ADR]
Operando inmediato
LD # NBR
AC = NBR
Direccionamiento indexado
LD ADR (X)
AC = M[ADR+ XR]
Registro
LD R1
AC = R1
Indirecto por registro
LD (R1)
AC = M [R1]
Autoincremento
LD (R1) +
AC = M[R1], R1 = R1 + 1
Cargar de inmediato se convierte en LDI. Otras normas del lenguaje
ensamblador utilizan un carácter especial para asignar el modo de
direccionamieto. Por ejemplo, el modo inmediato se reconoce por un signo #
colocado antes del operando. En cualquier caso, lo importante es entender que
cada instrucción puede ocurrir con diversos modos de direccionamiento. Como
ejemplo, consideremos la instrucción cargar al acumulador cuando se usa con
ocho modos de direccionamiento diferentes. La tabla 8-6 muestra la convención
recomendada del lenguaje ensamblador y la transferencia real que se logra en
cada caso. ADR representa una dirección, NBR es un número u operando, X es
un registro de índice, Rl es un registro de procesador, y AC es el registro
acumulador. El carácter 8 simboliza una dirección indirecta. El carácter $ antes
de una dirección hace el direccionamiento relativo al contador de programa PC.
El carácter $ precede al operando en una instrucción de modo inmediato. Una
instrucción de modo indexado se reconoce por un registro que se coloca entre
paréntesis después de la dirección simbólica. El modo de registro se simboliza al
proporcionar el nombre de un registro de procesador. En el modo indirecto por
registro, el nombre del registro que contiene la dirección de memoria se encierra
entre paréntesis. El modo de autoincremento se distingue del modo indirecto por
registro al colocar un signo de más después del registro entre paréntesis. A su
vez el modo de autodecremento utilizaría un signo de menos. Para poder escribir
programas del lenguaje ensamblador para una computadora es necesario conocer
el tipo de instrucciones disponibles y también estar familiarizado con .1os
modos de direccionamiento utilizados en la computadora particular.
http://members.fortunecity.es/roy8/cpu.htm
Unidad 3. Modularización
3.3 Macros.
MACROS.
Cuando un conjunto de instrucciones en ensamblador aparecen frecuentemente
repetidas a lo largo de un listado, es conveniente agruparlas bajo un nombre simbólico
que las sustituirá en aquellos puntos donde aparezcan. Esta es la misión de las macros;
por el hecho de soportarlas el ensamblador eleva su categoría a la de
macroensamblador, al ser las macros una herramienta muy cotizada por los
programadores.
No conviene confundir las macros con subrutinas: es estas últimas, el conjunto de
instrucciones aparece una sola vez en todo el programa y luego se invoca con CALL.
Sin embargo, cada vez que se referencia a una macro, el código que ésta representa se
expande en el programa definitivo, duplicándose tantas veces como se use la macro. Por
ello, aquellas tareas que puedan ser realizadas con subrutinas siempre será más
conveniente realizarlas con las mismas, con objeto de economizar memoria. Es cierto
que las macros son algo más rápidas que las subrutinas (se ahorra un CALL y un RET)
pero la diferencia es tan mínima que en la práctica es despreciable en el 99,99% de los
casos. Por ello, es absurdo e irracional realizar ciertas tareas con macros que pueden ser
desarrolladas mucho más eficientemente con subrutinas: es una pena que en muchos
manuales de ensamblador aún se hable de macros para realizar operaciones sobre
cadenas de caracteres, que generarían programas gigantescos con menos de un 1% de
velocidad adicional.
5.4.1. - DEFINICIÓN Y BORRADO DE LAS MACROS.
La macro se define por medio de la directiva MACRO. Es necesario definir la macro
antes de utilizarla. Una macro puede llamar a otra. Con frecuencia, las macros se
colocan juntas en un fichero independiente y luego se mezclan en el programa principal
con la directiva INCLUDE:
IF1
INCLUDE fichero.ext
ENDIF
La sentencia IF1 asegura que el ensamblador lea el fichero fuente de las macros sólo
en la primera pasada, para acelerar el ensamblaje y evitar que aparezcan en el listado
(generado en la segunda fase). Conviene hacer hincapié en que la definición de la macro
no consume memoria, por lo que en la práctica es indiferente declarar cientos que
ninguna macro:
nombre_simbólico MACRO [parámetros]
...
...
; instrucciones de la
macro
ENDM
El nombre simbólico es el que permitirá en adelante hacer referencia a la macro, y se
construye casi con las mismas reglas que los nombres de las variables y demás
símbolos. La macro puede contener parámetros de manera opcional. A continuación
vienen las instrucciones que engloba y, finalmente, la directiva ENDM señala el final de
la macro. No se debe repetir el nombre simbólico junto a la directiva ENDM, ello
provocaría un error un tanto curioso y extraño por parte del ensamblador (algo así como
«Fin del fichero fuente inesperado, falta directiva END»), al menos con MASM 5.0 y
TASM 2.0.
En realidad, y a diferencia de lo que sucede con los demás símbolos, el nombre de
una macro puede coincidir con el de una instrucción máquina o una directiva del
ensamblador: a partir de ese momento, la instrucción o directiva machacada pierde su
significado original. El ensamblador dará además un aviso de advertencia si se emplea
una instrucción o directiva como nombre de macro, aunque tolerará la operación.
Normalmente se las asignará nombres normales, como a las variables. Sin embargo, si
alguna vez se redefiniera una instrucción máquina o directiva, para restaurar el
significado original del símbolo, la macro puede ser borrada -o simplemente porque ya
no va a ser usada a partir de cierto punto del listado, y así ya no consumirá espacio en
las tablas de macros que mantiene en memoria el ensamblador al ensamblar-. No es
necesario borrar las macros antes de redefinirlas. Para borrarlas, la sintaxis es la
siguiente:
PURGE nombre_simbólico[,nombre_simbólico,...]
5.4.2. - EJEMPLO DE UNA MACRO SENCILLA.
Desde el 286 existe una instrucción muy cómoda que introduce en la pila 8 registros,
y otra que los saca (PUSHA y POPA). Quien esté acostumbrado a emplearlas, puede
crear unas macros que simulen estas instrucciones en los 8086:
SUPERPUSH
MACRO
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
ENDM
AX
CX
DX
BX
SP
BP
SI
DI
La creación de SUPERPOP es análoga, sacando los registros en orden inverso. El
orden elegido no es por capricho y se corresponde con el de la instrucción PUSHA
original, para compatibilizar. A partir de la definición de esta macro, tenemos a nuestra
disposición una nueva instrucción máquina (SUPERPUSH) que puede ser usada con
libertad dentro de los programas.
5.4.3. - PARÁMETROS FORMALES Y PARÁMETROS ACTUALES.
Para quien no haya tenido relación previa con algún lenguaje estructurado de alto
nivel, haré un breve comentario acerca de lo que son los parámetros formales y actuales
en una macro, similar aquí a los procedimientos de los lenguajes de alto nivel.
Cuando se llama a una macro se le pueden pasar opcionalmente un cierto número de
parámetros de cierto tipo. Estos parámetros se denominan parámetros actuales. En la
definición de la macro, dichos parámetros aparecen asociados a ciertos nombres
arbitrarios, cuya única misión es permitir distinguir unos parámetros de otros e indicar
en qué orden son entregados: son los parámetros formales. Cuando el ensamblador
expanda la macro al ensamblar, los parámetros formales serán sustituidos por sus
correspondientes parámetros actuales. Considerar el siguiente ejemplo:
SUMAR
MACRO a,b,total
PUSH
AX
MOV
AX,a
ADD
AX,b
MOV
total,AX
POP
AX
ENDM
....
SUMAR positivos, negativos, total
En el ejemplo, «a», «b» y «total» son los parámetros formales y «positivos»,
«negativos» y «total» son los parámetros actuales. Tanto «a» como «b» pueden ser
variables, etiquetas, etc. en otro punto del programa; sin embargo, dentro de la macro,
se comportan de manera independiente. El parámetro formal «total» ha coincidido en el
ejemplo y por casualidad con su correspondiente actual. El código que genera el
ensamblador al expandir la macro será el siguiente:
PUSH
MOV
AX
AX,positivos
ADD
MOV
POP
AX,negativos
total,AX
AX
Las instrucciones PUSH y POP sirven para no alterar el valor de AX y conseguir que
la macro se comporte como una caja negra; no es necesario que esto sea así pero es una
buena costumbre de programación para evitar que los programas hagan cosas raras. En
general, las macros de este tipo no deberían alterar los registros y, si los cambian, hay
que tener muy claro cuáles.
Si se indican más parámetros de los que una macro necesita, se ignorarán los
restantes. En cambio, si faltan, el MASM asumirá que son nulos (0) y dará un mensaje
de advertencia, el TASM es algo más rígido y podría dar un error. En general, se trata
de situaciones atípicas que deben ser evitadas.
También puede darse el caso de que no sea posible expandir la macro. En el ejemplo,
no hubiera sido posible ejecutar SUMAR AX,BX,DL porque DL es de 8 bits y la
instrucción MOV DL,AX sería ilegal.
5.4.4. - ETIQUETAS DENTRO DE MACROS. VARIABLES LOCALES.
Son necesarias normalmente para los saltos condicionales que contengan las macros
más complejas. Si se pone una etiqueta a donde saltar, la macro sólo podría ser
empleada una vez en todo el programa para evitar que dicha etiqueta aparezca
duplicada. La solución está en emplear la directiva LOCAL que ha de ir colocada justo
después de la directiva MACRO:
MINIMO
ya_esta:
MACRO
LOCAL
MOV
CMP
JB
MOV
MOV
ENDM
dato1, dato2,
ya_esta
AX,dato1
AX,dato2
ya_esta
AX,dato2
resultado,AX
resultado
; ¿es dato1 el menor?
; sí
; no, es dato2
En el ejemplo, al invocar la macro dos veces el ensamblador no generará la etiqueta
«ya_esta» sino las etiquetas ??0000, ??0001, ... y así sucesivamente. La directiva
LOCAL no sólo es útil para los saltos condicionales en las macros, también permite
declarar variables internas a los mismos. Se puede indicar un número casi indefinido de
etiquetas con la directiva LOCAL, separándolas por comas.
5.4.5. - OPERADORES DE MACROS.
* Operador ;;
Indica que lo que viene a continuación es un comentario que no debe aparecer al
expansionar la macro. Cuando al ensamblar se genera un listado del programa, las
macros suelen aparecer expandidas en los puntos en que se invocan; sin embargo sólo
aparecerán los comentarios normales que comiencen por (;). Los comentarios
relacionados con el funcionamiento interno de la macro deberían ir con (;;), los relativos
al uso y sintaxis de la misma con (;). Esto es además conveniente porque durante el
ensamblaje son mantenidos en memoria los comentarios de macros (no los del resto del
programa) que comienzan por (;), y no conviene desperdiciar memoria...
* Operador &
Utilizado para concatenar texto o símbolos. Es necesario para lograr que el
ensamblador sustituya un parámetro dentro de una cadena de caracteres o como parte de
un símbolo:
SALUDO
MACRO
MOV
etiqueta&c: CALL
ENDM
c
AL,"&c"
imprimir
Al ejecutar SALUDO A se producirá la siguiente expansión:
etiquetaA:
MOV
CALL
AL,"A"
imprimir
Si no se hubiera colocado el & se hubiera expandido como MOV AL,"c"
Cuando se utilizan estructuras repetitivas REPT, IRP o IRPC (que se verán más
adelante) existe un problema adicional al intentar crear etiquetas, ya que el ensamblador
se come un & al hacer la primera sustitución, generando la misma etiqueta a menos que
se duplique el operador &:
MEMORIA
x&i
MACRO
IRP
DB
ENDM
ENDM
x
i, <1, 2>
i
Si se invoca MEMORIA ET se produce el error de "etiqueta ETi repetida", que se
puede salvar añadiendo tantos '&' como niveles de anidamiento halla en las estructuras
repetitivas empleadas, como se ejemplifica a continuación:
MEMORIA
x&&i
MACRO
IRP
DB
ENDM
ENDM
x
i, <1, 2>
i
Lo que con MEMORIA ET generará correctamente las líneas:
ET1
ET2
DB 1
DB 2
* Operador ! o <>
Empleado para indicar que el carácter que viene a continuación debe ser
interpretado literalmente y no como un símbolo. Por ello, !; es equivalente a <;>.
* Operador %
Convierte la expresión que le sigue -generalmente un símbolo- a un número; la
expresión debe ser una constante (no relocalizable). Sólo se emplea en los argumentos
de macros. Dada la macro siguiente:
PSUM
MACRO
%OUT
mensaje, suma
* mensaje, suma *
ENDM
(Evidentemente, el % que precede a OUT forma parte de la directiva y no se trata
del % operador que estamos tratando)
Supuesta la existencia de estos símbolos:
SIM1
SIM2
EQU
EQU
120
500
Invocando la macro con las siguientes condiciones:
PSUM
< SIM1 + SIM2 = >, (SIM1+SIM2)
Se produce la siguiente expansión:
%OUT * SIM1 + SIM2 = (SIM1+SIM2) *
Sin embargo, invocando la macro de la siguiente manera (con %):
PSUM < SIM1 + SIM2 = >, %(SIM1+SIM2)
Se produce la expansión deseada:
%OUT * SIM1 + SIM2 = 620 *
5.4.6. - DIRECTIVAS ÚTILES PARA MACROS.
Estas directivas pueden ser empleadas también sin las macros, aumentando la
comodidad de la programación, aunque abundan especialmente dentro de las macros.
* REPT veces ... ENDM (Repeat)
Permite repetir cierto número de veces una secuencia de instrucciones. El bloque
de instrucciones se delimita con ENDM (no confundirlo con el final de una macro). Por
ejemplo:
REPT
OUT
ENDM
2
DX,AL
Esta secuencia se transformará, al ensamblar, en lo siguiente:
OUT
OUT
DX,AL
DX,AL
Empleando símbolos definidos con (=) y apoyándose además en las macros se
puede llegar a crear pseudo-instrucciones muy potentes:
SUCESION
MACRO n
num = 0
REPT n
DB num
num = num + 1
ENDM
ENDM
; fin de REPT
; fin de macro
La sentencia SUCESION 3 provocará la siguiente expansión:
DB
DB
DB
0
1
2
* IRP simbolo_control, <arg1, arg2, ..., arg_n> ... ENDM (Indefinite repeat)
Es relativamente similar a la instrucción FOR de los lenguajes de alto nivel. Los
ángulos (<) y (>) son obligatorios. El símbolo de control va tomando sucesivamente los
valores (no necesariamente numéricos) arg1, arg2, ... y recorre en cada pasada todo el
bloque de instrucciones hasta alcanzar el ENDM (no confundirlo con fin de macro)
sustituyendo simbolo_control por esos valores en todos los lugares en que aparece:
IRP
DB
ENDM
i, <1,2,3>
0, i, i*i
Al expansionarse, este conjunto de instrucciones se convierte en lo siguiente:
DB
DB
DB
0, 1, 1
0, 2, 4
0, 3, 9
Nota: Todo lo encerrado entre los ángulos se considera un único parámetro. Un (;)
dentro de los ángulos no se interpreta como el inicio de un comentario sino como un
elemento más. Por otra parte, al emplear macros anidadas, deben indicarse tantos
símbolos angulares '<' y '>' consecutivos como niveles de anidamiento existan.
Lógicamente, dentro de una macro también resulta bastante útil la estructura IRP:
TETRAOUT
MACRO
PUSH
PUSH
MOV
IRP
MOV
OUT
ENDM
POP
POP
ENDM
p1, p2, p3, p4, valor
AX
DX
AL,valor
cn, <p1, p2, p3, p4>
DX, cn
DX, AL
; fin de IRP
DX
AX
; fin de macro
Al ejecutar TETRAOUT 318h, 1C9h, 2D1h, 1A4h, 17 se obtendrá:
PUSH
PUSH
MOV
MOV
OUT
MOV
OUT
MOV
OUT
MOV
OUT
POP
POP
AX
DX
AL, 17
DX, 318h
DX, AL
DX, 1C9h
DX, AL
DX, 2D1h
DX, AL
DX, 1A4h
DX,AL
DX
AX
Cuando se pasan listas como parámetros hay que encerrarlas entre '<' y '>' al
llamar, para no confundirlas con elementos independientes. Por ejemplo, supuesta la
macro INCD:
INCD
MACRO
IRP
INC
ENDM
DEC
ENDM
lista, p
i, <lista>
i
; fin de IRP
p
Se comprende la necesidad de utilizar los ángulos:
INCD AX, BX, CX, DX se expandirá:
; fin de macro
INC
DEC
AX
BX ; CX y DX se ignoran (4
parámetros)
INCD <AX, BX, CX>, DX se expandirá:
INC
INC
INC
DEC
AX
BX
CX
DX
; (2 parámetros)
* IRPC simbolo_control, <c1c2 ... cn> ... ENDM (Indefinite repeat character)
Esta directiva es similar a la anterior, con una salvedad: los elementos situados
entre los ángulos (<) y (>) -ahora opcionales, por cierto- son caracteres ASCII y no van
separados por comas:
IRPC
DB
ENDM
i, <813>
i
El bloque anterior generará al expandirse:
DB
DB
DB
8
1
3
Ejemplo de utilización dentro de una macro (en combinación con el operador &):
INICIALIZA
MACRO
IRPC
DB
ENDM
ENDM
a, b, c, d
iter, <&a&b&c&d>
iter
; fin de IRPC
; fin de macro
Al ejecutar INICIALIZA 7, 1, 4, 0 se produce la siguiente expansión:
DB
DB
DB
DB
7
1
4
0
* EXITM
Sirve para abortar la ejecución de un bloque MACRO, REPT, IRP ó IRPC.
Normalmente se utiliza apoyándose en una directiva condicional (IF...ELSE...ENDIF).
Al salir del bloque, se pasa al nivel inmediatamente superior (que puede ser otro bloque
de estos). Como ejemplo, la siguiente macro reserva n bytes de memoria a cero hasta un
máximo de 100, colocando un byte 255 al final del bloque reservado:
MALLOC
MACRO n
maximo=100
REPT n
IF maximo EQ 0
; ¿ya van 100?
EXITM
; abandonar REPT
ENDIF
maximo = maximo - 1
DB 0
; reservar byte
ENDM
DB 255
; byte de fin de
bloque
ENDM
5.4.7. - MACROS AVANZADAS CON NUMERO VARIABLE DE PARÁMETROS.
Como se vio al estudiar la directiva IF, existe la posibilidad de chequear
condicionalmente la presencia de un parámetro por medio de IFNB, o su ausencia con
IFB. Uniendo esto a la potencia de IRP es posible crear macros extraordinariamente
versátiles. Como ejemplo, valga la siguiente macro, destinada a introducir en la pila un
número variable de parámetros (hasta 10): es especialmente útil en los programas que
gestionan interrupciones:
XPUSH
MACRO R1,R2,R3,R4,R5,R6,R7,R8,R9,R10
IRP reg, <R1,R2,R3,R4,R5,R6,R7,R8,R9,R10>
IFNB <reg>
PUSH reg
ENDIF
ENDM
; fin de IRP
ENDM
; fin de XPUSH
Por ejemplo, la instrucción:
XPUSH
AX,BX,DS,ES,VAR1
PUSH
PUSH
PUSH
PUSH
PUSH
AX
AX
DS
ES
VAR1
Se expandirá en:
El ejemplo anterior es ilustrativo del mecanismo de comprobación de presencia de
parámetros. Sin embargo, este ejemplo puede ser optimizado notablemente empleando
una lista como único parámetro:
XPUSH
MACRO lista
IRP i, <lista>
PUSH i
ENDM
ENDM
XPOP
MACRO lista
IRP i, <lista>
POP i
ENDM
ENDM
La ventaja es el número indefinido de parámetros soportados (no sólo 10). Un
ejemplo de uso puede ser el siguiente:
XPUSH
XPOP
<AX, BX, CX>
<CX, BX, AX>
PUSH
PUSH
PUSH
POP
POP
POP
AX
BX
CX
CX
BX
AX
Que al expandirse queda:
http://meltingpot.fortunecity.com/uruguay/978/libro/05.html#04
MACRO.- Sirve para definir una Macro.
Una macro, es un conjunto de instrucciones que se pueden mandar a llamar
desde cualquier parte del programa.
Para definir una macro, se utiliza la directiva MACRO. El formato de esta
directiva es :
(nombre_de_macro) MACRO (lista_parámetros)
La macro consta de tres partes esenciales: la cabecera, que contiene el
nombre de la macro, la directiva MACRO y una lista opcional de parámetros; el
cuerpo, que contiene el código de la macro, y el fin, que contiene simplemente
la directiva ENDM.
Ejemplo :
INIT2
MACRO
MOV
MOV
MOV
ENDM
AX,DATA
DS,AX
ES,AX
La mayoría de las programas ejecutan conjunto de instrucciones repetitivas.
Por ejemplo para desplegar un mensaje es necesario ejecutas la siguiente
secuencia de instrucciones:
MOV DX, FOCET MENSAJE
MOV AH, 09H
INT 21
Si su programa realiza frecuentemente funciones de entrada/salida, las
macros ofrecen la facilidad de codificar una sola vez un conjunto de
instrucciones y reutilizar el código cuantas veces desee dentro de su programa.
Una macro es una pseudo-op que permite el establecimiento de
operaciones únicas en ensamblador o la inclusión de frecuentes llamadas de
código ensamblador. Una macro también se puede definir como un grupo de
instrucciones repetitivas en un programa que se codifica sólo una vez y puede
utilizarse cuantas veces sea necesario.
Una macro consta de tres partes esenciales:
a) CABECERA: Contiene el nombre de la macro, la pseudo-op MACRO y
opcionalmente, variables ficticias que serán pasadas desde la macro.
b) CUERPO: Contiene el código real que será insertado en cualquier programa
que llame al nombre de la macro.
c) FIN: Debe incluir la sentencia ENDM.
El formato de definición de una macro es :
NombreMacro MACRO (parámetro1, parámetro2,..., parámetroN)
CUERPO DE LA MACRO
ENDM
Ejemplo de la definición de una macro.
INICIO MACRO
;DEFINE MACRO
MOV AX, DATA
;CUERPO DE
MOV DS, AX
;LA DEFINICIÓN
MOV ES, AX
;DE LA MACRO
ENDM
;FIN DE LA MACRO
El nombre de esta macro es INICIO, aunque es aceptable cualquier otro
nombre válido que sea único. La directiva MACRO en la primer línea indica al
ensamblador que las instrucciones que siguen, hasta ENDM (“fin de la macro”),
son parte de la definición de la macro.
La directiva ENDM termina la definición de la macro. Las instrucciones entre
MACRO y ENDM comprenden el cuerpo de la definición de la macro.
Los nombres a que se hace referencia en la definición de la macro,
@datos, AX, DS y ES, deben estar definidos en alguna parte del programa o
deben ser dados a conocer de alguna otra forma al ensamblador. .En forma
subsecuente se puede usar la macroinstrucción INIICIO en el segmento de
código en donde quiera inicializar los registros. Cuando el ensamblador
encuentra la macroinstrucción INICIO, el ensamblador copia el cuerpo de la
macro en la posición del programa dónde se encuentra la llamada a la macro.
PARÁMETROS
Un parámetro es una variable que puede tomar un valor diferente cada vez
que se ejecute una subrutina en la que se utiliza tal variable.
Los parámetros son reemplazados por los nombres o valores que
especifique la instrucción que la invocó. La lista de parámetros es opcional y, si
existe, cada parámetro deberá estar separado por una coma.
Ejemplo:
Despliega MACRO Mensaje
Toda macro tiene une definición inicial que consta del nombre asignado a
ella, el seudocódigo de operación MACRO y la lista de parámetros. En la
definición anterior el nombre de la macro es despliega y su parámetro es
mensaje (el mensaje que se desplegará cada vez que sea invocada la macro).
Despliega MACRO Mensaje
MOV
DX, OFFSE Mensaje
MOV
AH, 09
INT
21H
ENDM
Para hacer una macro flexible, podemos definir nombres en ella como
argumentos mudos (ficticios). La definición de la macro siguiente llamada
PROMPT, proporciona el uso de la función 09H del DOS para desplegar
cualquier mensaje, cuando se usa la macro instrucción, el programador tiene
que proporcionar el nombre del mensaje, el cual hace referencia a un área de
datos determinada por un signo de dólar.
PROMPT MACRO MENSAJE ;ARGUMENTO MUDO
MOV AH,09H
LEA DX;MESSGE
INT
21H
ENDM
;FIN DE LA MACRO
Un argumento mudo (ficticio) indica al ensamblador que haga coincidir su
nombre con cualquier aparición del mismo nombre en el cuerpo de la macro.
Por ejemplo el argumento mudo MENSAGE también aparece en la instrucción
LEA.
Cuando utiliza la macro instrucción PROMPT, usted proporciona un
parámetro como el nombre real del mensaje que será desplegado, por ejemplo:
PROMPT MESSAGE2
En este caso MESSAGE2 tiene que estar apropiadamente definido en el
segmento de datos. El parámetro en la macroinstrucción corresponde al
argumento mudo en la definición original de la macro:
DEFINICIÓN DE MACRO: PROMPT MACRO MESSAGE (argumento)
MACROINSTRUCCIÓN: PROMPT MESSAGE2
(parámetro)
El ensamblador sustituye los parámetros de la macroinstrucción por los
argumentos mudos en la definición de la macro, entrada por entrada, de
izquierda a derecha.
Ejemplo de parámetros de macros.
TITLE
P22MACR2 (EXE) USO DE PARÁMETROS.
INITZ MACRO ;DEFINE MACRO
MOV AX, DATA
MOV DS,AX
MOV ES,AX
ENDM ;TERMINA MACRO
PROMPT
MACRO MESSGE ;DEFINE MACRO
MOV AH, 09H
LEA DS, MESSGE
INT 21H
ENDM ;TERMINA MACRO
.MODEL SMALL
.STACK 64
.DATA
MESSGE1 DB ‘CUSTOMER NAME?’, ‘$’
MESSG2 DB ‘CUSTOMER ADDRES’, ‘$’
.CODE
BEGIN PROC FAR
INITZ
MOV AX, DATA
MOV DS, AX
MOV ES, AX
PROMPT MESSG2
MOV AH, 09H
LEA DX, MESSG2
INT 21H
MOV AX, 4C00H ;SALE AL DOS
INT 21H
BEGIN ENDP
END BEGIN
ETIQUETAS
Una etiqueta es el primer campo de la izquierda de una línea. Este campo
es opcional, consiste en un conjunto de caracteres y sirve para identificar dicha
línea.
Cuando en una línea de instrucción se encuentra una etiqueta el ordenador
guardará dicha etiqueta junto con la dirección que le ha correspondido a la
instrucción para posteriormente ser relacionada con una instrucción de salto a
esa dirección.
Con el uso de etiquetas el programador se despreocupa de las posiciones
de memoria que van a ocupar las instrucciones y coloca etiquetas a las
instrucciones a las que haga referencia en otros puntos del programa.
A continuación se mencionan algunas ventajas que ofrece el empleo de
etiquetas:
a) Permite localizar y recordar fácilmente una determinada instrucción.
b) Se puede modificar de forma sencilla, en la fase de corrección de un
programa, el punto donde tienen que realizarse uno o más saltos cambiando la
etiqueta de una instrucción a otra.
c) En caso de que el programa objeto de debe colocar en posiciones de
memoria diferentes de las que en un principio se había previsto. No hay que
hacer ningún cambio en el programa fuente si se han utilizado etiquetas, pues
al hacer la nueva traducción asigna automáticamente las nuevas posiciones a
las etiquetas. Esto facilita la unión de varios programas que han sido
desarrollados por separado.
Ejemplo de una etiqueta:
Despliega MACRO Mensaje, Veces
MOV CX, Veces
OTRA: MOV DX, OFFSET Mensaje
MOV AH,9
INT 21H
LOOP OTRA
ENDM
La macro anterior despliega el mensaje las veces especificadas. Sin
embargo, ¿qué sucede si invoca usted la macro más de una vez?. El TASM
genera un error de etiqueta redefinida porque no se puede definir una etiqueta
con el mismo nombre más de una vez (la etiqueta de la macro anterior es
OTRA). Las normas para definición de etiquetas nos dicen que éstas deben
tener nombres únicos; lo anterior se debe a que si el TASM permitiese la
duplicación de etiquetas, el programa se vería en un predicamento porque no
podría decidir a cuál de las etiquetas debe hacerle caso.
Ejemplo:
...CÓDIGO
.
.
Despliega MACRO Mensaje, veces
MOV CX, Veces
OTRA:
MOV DX,OFFSET Mensaje
MOV AH,09
INT 21H
LOOP OTRA
ENDM
...MAS CÓDIGO
.
.
.
MOV CX,10
OTRA:
LOOP OTRA
...RESTO DEL CÓDIGO
...END PROGRAMA
Cuando el programa ejecuta la primera macro todo está bien, pero cuando
intenta ejecutar el código que contiene de nuevo el mismo nombre de etiqueta
se queda perplejo porque no puede decidir si la interacción se aplica a su
etiqueta OTRA o a la etiqueta OTRA de la macro procesadora.
Afortunadamente existe una solución al problema que consiste en usar un
seudocódigo de operación llamado LOCAL, el cual enumera todas las
etiquetas utilizadas dentro de una macro. Cada vez que la macro sea
expandida, el TASM crea un símbolo único para cada etiqueta enumerada en
la lista de LOCAL. El formato de LOCAL es:
LOCAL lista de etiquetas
Donde lista de etiquetas es la lista de los nombres de etiqueta que se
usarán dentro de la macro. LOCAL debe ser la primera instrucción que
aparezca tras la definición de la macro, ya que no pueden haber comentarios
entre la definición y la especificación de LOCAL. Teniendo presente lo anterior
redefinamos la macro anterior.
Despliega MACRO Mensaje, Veces
LOCAL OTRA
MOV CX, VECES
OTRA: MOV DX, OFFSET Mensaje
MOV AH,9
INT 21H
LOOP OTRA
ENDM
ENSAMBLE DE MACROS
Al ensamblarse una macro de un programa en lenguaje ensamblador, lo que
hace él turbo asembler (Tasm) de Borland turbo pascal es: buscar el código de
la macro, copiarlo y pegarlo en cada una de las macros existentes del
programa.
Cuando se crea un programa no es necesario escribir los comentarios que
van después de las comillas, sin embargo es una técnica recomendable para
que en caso de errores o mejoras al código sea más sencillo encontrar la parte
deseada.
Para ensamblar este programa primero se guarda el formato ASCII con un
nombre válido, por ejemplo:
program1.asm
Para ensamblarlo se utiliza el TASM, el comando de ensamble es: TASM
Program1; para enlazarlo y hacerlo ejecutable tecleamos: LINK program1;
Una vez terminados estos pasos es posible ejecutarlo tecleando: program1
[Enter]
Para utilizar el programa directamente en su computadora guarde este
archivo como ASCII o texto, llévelo a su PC, con algún editor elimine todos
estos comentarios y los comentarios del principio y ensámblelo.
PROGRAMA:
; INICIO DEL PR0GRAMA, DEFINIMOS EL MODELO DE MEMORIA A USAR Y EL
SEGMENTO
; DE CÓDIGO
.MODEL SMALL ;MODELO DE MEMORIA
.CODE ;ÁREA DE CÓDIGO
INICIO: ;ETIQUETA DE INICIO DEL PROGRAMA
MOVE AX,DATA ;INICIALIZA EL REGISTRO DS CON LA
DIRECCIÓN DADA
MOV DS,AX
;POR DATA (SEGMENTO DE DATOS)
MOV DX, OFFSET Titulo
;OBTIENE LA DIRECCIÓN DE LA CADENA DE
CADENA DE CARACTERES
MOV AH,09
;USAMOS LA FUNCIÓN 09H DE LA
INTERRUPCIÓN 21H
INT 21H ;PARA DESPLEGAR LA CADENA CUYA
DIRECCIÓN OBTUVIMOS
MOV CX,16 ;CONTADOR DE CARACTERES QUE SE
MOSTRARÁ
MOV BX,OFFSET Cadena ;PERMITE ACCESO A LA CADENA DONDE SE
ENCUENTRAN LOS VALORES A DESPLEGAR
CICLO: ;ETIQUETA PARA GENERAR UN CICLO
MOV AL,CL ;COLOCA EN AL EL NÚMERO A TRADUCIR Y
LO TRADUCE
XLAT ;USANDO LA INSTRUCCIÓN XLAT
MOV DL,AL ;COLOCA EN DL EL VALOR A SER
DESPLEGADO POR MEDIO DE
LA
MOV AH, 02
;FUNCIÓN 2 DE LA INTERRUPCIÓN 21H
INT 21H ;DESPLIEGA EL CARACTER
MOV DL,10 ;SALTA UNA LÍNEA DESPLEGANDO EL
CARÁCTER 10
INT 21H ;DESPLIEGA EL CARACTER
MOV DL,13 ;PRODUCE UN RETORNO DE CARRO
DESPLEGANDO EL
CARACTER 13
INT 21H ;DESPLIEGA EL RETORNO DE CARRO
LOOP CICLO ;DECREMENTA EN 1 A CX Y BRINCA LA
ETIQUETA CICLO
;SIEMPRE Y CUANDO CX NO SEA IGUAL A
CERO
MOV AH, 4C ; UTILIZA LA FUNCIÓN 4C DE LA INTERRUPCIÓN 21H PARA
INT 21H ;FINALIZAR EL PROGRAMA
VENTAJAS DE LAS MACROS
1: Las macros son rápidas porque se ejecutan en línea en un programa.
2: Las macros pueden pasar y recibir parámetros que afecten solo la operación
de las mismas.
3: Las macros pueden ser guardadas en una biblioteca en código fuente, que
puede ser fácilmente editada.
4: La cabecera de programación puede utilizar macros simple; para una
biblioteca de macros utilizar IF1...ENDIF.
DESVENTAJAS DE LAS MACROS
1: Las macros hacen más grande el código fuente, ya que son expandidas
cada vez que son llamadas.
Definición
Una de las principales desventajas de la programación en lenguaje
ensamblador es la repetición constante de ciertos grupos de instrucciones. Por
ejemplo el siguiente conjunto de instrucciones nos permite imprimir una
variable de tipo cadena en la pantalla:
Lea DX,Cadena ;Direccionar la cadena
Mov AH,09h ;Usar la función 09h para imprimir cadenas
Int 21h ;llamada a la interrupción 21h del DOS
Si necesitamos que en nuestro programa se muestren mensajes
constantemente, es obvio que debemos duplicar este conjunto de instrucciones
por cada mensaje que se desea enviar a pantalla.
El principal problema que esto nos ocasiona es que el tamaño de nuestro
programa crece considerablemente, y mientras más grande sea el programa,
más difícil será encontrar la causa de algún error cuando éste ocurra.
La mejor solución en estos casos es el uso de las MACROS. Una macro es un
conjunto de instrucciones que se agrupan bajo un nombre descriptivo
(macroinstrucción) y que sólo es necesario declarar una vez (macrodefinición).
Una vez que la macro ha sido declarada, sólo es necesario indicar su nombre
en el cuerpo del programa y el ensamblador se encargara de reemplazar la
macroinstrucción por las instrucciones de la macro (expansión de la macro).
El formato general de una macro es el siguiente:
.MACRO Nombre [(parametro1, parametro2, etc)]
INSTRUCCIONES
ENDM
Nuevamente, lo que se encuentra entre paréntesis cuadrados es opcional.
De acuerdo con esto, la macro para imprimir cadenas quedaría de la siguiente
forma:
.MACRO Imprime_Cad(Cadena)
Lea DX,Cadena
Mov Ah,09h
Int 21h
ENDM
Parámetros y etiquetas
Dentro de las propiedades más importantes de las macros se deben destacar
la posibilidad de utilizar parámetros y etiquetas.
Los parámetros permiten que una misma macro pueda ser usada bajo
diferentes condiciones, por ejemplo, se puede crear una macro para posicionar
el cursor en diferentes coordenadas de la pantalla e indicar sus coordenadas
por medio de parámetros.
La siguiente macro nos muestra esta propiedad:
;Esta macro posiciona el cursor en las coordenadas que se le indican como
;parámetros. Es el equivalente al GotoXY de Pascal.
.MACRO gotoxy (x,y)
xor bh,bh ;Seleccionar página cero de video
mov dl,x ;Columna
mov dh,y ;Renglón
mov ah,02h ;Función 02h para posicionar cursor
int 10h ;llamada a la int 10h del BIOS
ENDM
También existen situaciones en las que los parámetros no son necesarios, es
por esta razón que los parámetros son opcionales en la declaración de la
macro.
;Esta macro realiza una pausa en el programa hasta que una tecla es
;presionada. Es el equivalente del readkey en Pascal.
.MACRO tecla
mov ah,10h
int 16h
ENDM
Por otro lado, las etiquetas también son útiles dentro de las macros. Suponga
que se desea crear una macro que imprima una cadena un numero n de veces,
esta macro podría ser declarada de la siguiente forma:
.MACRO Imprime_nCad (Cadena, Cuantos)
Mov CX,Cuantos ;Iniciar Contador
Lea DX,Cadena ;Direccionar la cadena que se va a imprimir
Mov Ah,09h ;Usar la función 09h
Otra: ;Etiqueta interna
Int 21h ;Imprimir la Cadena n veces
Loop Otra ;Siguiente Impresión
ENDM
Ensamble de macros
Como ya se mencionó antes, una macro es declarada una sola vez y puede ser
llamada cuantas veces sea necesario dentro del cuerpo del programa.
Cada vez que el ensamblador encuentra una macroinstrucción, verifica si ésta
fue declarada; si esta verificación es exitosa, el ensamblador toma las
instrucciones del cuerpo de la macro y las reemplaza en el lugar donde la
macro fue llamada.
El siguiente programa muestra la declaración y uso de las macros:
.COMMENT
Programa: Macros1.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa muestra el uso de macros.
.MODEL TINY
; Declaración de variables
.DATA
cad db 'Ejemplo del uso de macros...',13,10,'$'
cad1 db 'Presiona una tecla...','$'
cad2 db 'Ejemplo del uso de la macro gotoxy...','$'
;Aquí se declaran las macros.
;************************************************************************
;-----------------------------------------------------------------------;Esta macro imprime una cadena pasada como parámetro.
;Utiliza la función 09h de la Int 21h del DOS.
.MACRO imprime_cad(cadena)
lea dx,cadena
mov ah,09h
int 21h
ENDM
;-----------------------------------------------------------------------;Esta macro realiza una pausa en el programa hasta que una tecla se
;presione. Es el equivalente del readkey en Pascal.
.MACRO tecla
mov ah,10h
int 16h
ENDM
;-----------------------------------------------------------------------;Esta macro posiciona el cursor en las coordenadas que se le indican como
;parámetros. Es el equivalente al GotoXY de Pascal.
.MACRO gotoxy (x,y)
xor bh,bh
mov dl,x
mov dh,y
mov ah,02h
int 10h
ENDM
;------------------------------------------------------------;Esta macro limpia la pantalla.
;Utiliza la función 06h de la Int 10h del Bios.
.MACRO limpiar_pantalla
mov ax,0600h
mov bh,17h
mov cx,0000h
mov dx,184fh
int 10h
ENDM
;------------------------------------------------------------;Aquí comienza el cuerpo del programa principal
.CODE
inicio: ;Declaración del punto de entrada
limpiar_pantalla ;Llamada a la macro
gotoxy (0,0) ;Colocar el cursor en 0,0
imprime_cad(cad) ;Imprime el primer mensaje
imprime_cad(cad1) ;Imprime el segundo mensaje
tecla ;Espera a que se presione una tecla
gotoxy (30,12) ;Colocar el cursor en 30,12
imprime_cad(cad2) ;Imprimir el tercer mensaje
gotoxy (50,24) ;Colocar el cursor en 50,24
imprime_cad(cad1) ;Imprimir el segundo mensaje
tecla ;Esperar por una tecla
mov ax,4c00h ;Fin del programa y regresar al DOS.
int 21h
END inicio
END
Ventajas y desventajas
Si bien es cierto que las macros proporcionan mayor flexibilidad a la hora de
programar, también es cierto que tienen algunas desventajas.
La siguiente es una lista de la principales ventajas y desventajas del uso de las
macros.
Ventajas:




Menor posibilidad de cometer errores por repetición.
Mayor flexibilidad en la programación al permitir el uso de parámetros.
Código fuente más compacto.
Al ser más pequeño el código fuente, también es más fácil de leer por otros.
Desventajas:


El código ejecutable se vuelve más grande con cada llamada a la macro.
Las macros deben ser bien planeadas para evitar la redundancia de código.
http://www.monografias.com/trabajos11/lenen/lenen2.s
html
Conceptos básicos
Definición y operación
Una macro es un símbolo que representa un bloque de texto.
El ensamblador usa las macros de tal manera que cada vez que encuentra al símbolo que
define la macro, lo sustituye por el texto que representa.
Cómo crear macros
Sintaxis:
<Nombre> MACRO [parametros]
...
ENDM
Ejemplo:
DuplicaAL MACRO
SHL AL, 1
ENDM
Código que la usa:
MOV AL, 2
DuplicaAL ; Esta es la "llamada" al macro
El ensamblador sustituye cada vez que aparezca la macro
No es como los procedimientos, que se "llaman" pero no repiten el código
Ejemplo:
MOV AL, 2
DuplicaAL ; CALL Duplica
DuplicaAL ; CALL Duplica
Este código queda
MOV AL, 2
SHL AL, 1 ; CALL Duplica
SHL AL, 1 ; CALL Duplica
Cúando usarlas y cúando no



Cuando se quiere el código más rápido y no importa ser repetitivo (código
grande)
Cuando se van a generar diversas variantes de código similar
No cuando se quiere código compacto, evitando repetir el mismo (en este caso,
usar procedimientos)
Asignación de variables y constantes para el ensamblador
Pseudoinstrucciones, pues solamente se usan durante el proceso de traducción
Sintaxis:
<Simbolo> EQU Valor
<Simbolo> = Valor
Permiten definir constantes y variables del ensamblador
La diferencia es que = puede usarse varias veces sobre el mismo símbolo (como una
variable)
REPT
Directiva para definir bloques repetitivos
Permite repetir un código determinado, tantas veces como se desee
Sintaxis:
REPT <n>
...
ENDM
Ejemplo:
Valor = 0 ; Variable de ensamblador
REPT 10
DW Valor
Valor = Valor + 1
ENDM
Uso de parámetros en macros
Los macros pueden ser adaptativos; por ejemplo:
Potencia2 MACRO Registro, Valor
REPT Valor
SHL Registro, 1
ENDM
ENDM
Uso:
Potencia2 CX, 4
Se convierte en:
SHL CX, 1
SHL CX, 1
SHL CX, 1
SHL CX, 1
http://www.sinergia-web.com.mx/clases/asm9708/Temas/clase18.htm
Para cada instrucción simbólica que usted codifica, el ensamblador
genera una instrucción de lenguaje de maquina. El ensamblador tiene
facilidades que el programador puede utilizar para definir macros.
Primero hay que definir un nombre especifico para la macro, junto con
el conjunto de instrucciones en lenguaje ensamblador que la macro va
a generar. Después, siempre que necesite codificar el conjunto de
instrucciones, solo hay que codificar el nombre de la macro y el
ensamblador genera de forma automática las instrucciones que han
sido definidas en la macro.
Las macros son útiles para los siguientes propósitos:



Simplificar y reducir la cantidad de codificación repetitiva.
Reducir errores causados por la codificación repetitiva.
Linealizar un programa en lenguaje ensamblador para hacerlo
mas legible.
Una definición de macro aparece antes de que cualquier definición de
segmento. Examinemos una definición de una macro sencilla que
inicializa los registros de segmento para un programa.EXE:
INICIAREGS
MACRO
MOV AX, @data
MOV DS, AX
MOV ES, AX
ENDM
;Define macro
; } Cuerpo de
; } la definición
; } de la macro
; Fin de la macro
El nombre de esta macro es INICIAREGS, aunque es aceptable
cualquier otro nombre valido que sea único. La directiva MACRO en la
primer línea indica al ensamblador que las instrucciones que siguen,
hasta ENDM ("fin de la macro"), son parte de la definición de la macro.
La directiva ENDM termina la definición de la macro.
Los nombres a que se hace referencia en la definición de la macro,
@data, AX, DS y ES, deben estar definidos en alguna parte del
programa o deben ser dados a conocer de alguna otra forma al
ensamblador.
En forma subsecuente se puede usar la macro-instruccion
INICIAREGS en el segmento de código en donde quiera inicializar los
registros. Cuando el ensamblador encuentra la macra-instruccion
INICIAREGS, busca en una tabla de instrucciones simbólicas y, a falta
de una entrada, busca macroinstrucciones. Ya que el programa
contiene una definición de la macro INICIAREGS, el ensamblador
sustituye el cuerpo de la definición generando instrucciones: la
expansión de la macro.
Un programa usaría la macroinstruccion INICIAREGS solo una vez,
aunque otras macros están diseñadas para ser utilizadas cualquier
numero de veces y cada vez el ensamblador genera la misma
expansión.
MANEJO DE PARAMETROS.
Para hacer una macro flexible, puede definir nombres en ella como
argumentos mudos (ficticios).La definición de la macro siguiente,
llamada DESPLEGAR_MSG, proporciona el uso de la función 09H del
DOS para desplegar cualquier mensaje. Cuando se usa la
macroinstrucción el programador tiene que proporcionar el nombre del
mensaje, el cual hace referencia a un área de datos terminada por un
signo de dólar.
DESPLEGAR_MSG
MACRO MENSAJE
MOV AH, 09H
LEA DX, MENSAJE
INT
21H
ENDM
; Argumento mudo
; Fin de la macro
Un argumento mudo en una definición de macro indica al ensamblador
que haga coincidir su nombre con cualquier aparición del mismo
nombre en el cuerpo de la macro. Por ejemplo, el argumento mudo
MENSAJE también aparece en la instrucción LEA.
Cuando utiliza la macroinstrucción DESPLEGAR_MSG, usted
proporciona un parámetro como el nombre real del mensaje que será
desplegado, por ejemplo:
DESPLEGAR_MSG MENSAJE2
En este caso, MENSAJE2 tiene que estar apropiadamente definido en
el segmento de dato. El parámetro en la microinstrucción corresponde
al argumento mudo en la definición original de la macro:
Definición de macro: DESPLEGAR_MSG MACRO MENSAJE
(Argumento)
Macroinstruccin:
DESPLEGAR_MSG MENSAJE2
(Parametro)
El ensamblador ya ha hecho corresponder el argumento en la
definición original de la macro con la instrucción LEA en el cuerpo de
la macro. Ahora sustituye el (los) parámetro(s) de la macroinstrucción
MENSAJE2 por la presencia de MENSAJE en la instrucción LEA y la
sustituye por cualquier otra aparición de MENSAJE.
Un argumento mudo puede contener cualquier nombre valido,
incluyendo un nombre de registro tal como CX. Puede definir una
macro con cualquier numero de argumentos mudos, separados por
coma, hasta la columna 120 de una línea. El ensamblador sustituye
los parámetros de la macro instrucción por los argumentos mudos en
la definición de la macro, entrada por entrada, de izquierda a derecha.
MANEJO DE ETIQUETAS LOCALES.
Algunas macros necesitan que se definan elementos de datos y
etiquetas de instrucciones dentro de la definición de la macro. Si utiliza
la macro mas de una vez en el mismo programa y el ensamblador
define los elementos de datos para cada aparición, los nombres
duplicados harían que el ensamblador genere un mensaje de error.
Para asegurar que cada nombre generado es único, hay que codificar
la directiva LOCAL inmediatamente después de la instrucción
MACRO. Su formato general es:
LOCAL Etiqueta1, Etiqueta2...Etiquetan.
BIBLIOTECAS DE MACROS.
Definir una macro y usarla solo una vez en un programa no es muy
productivo. El enfoque habitual es catalogar las macros en una
biblioteca en disco bajo un nombre descriptivo, como MACRO.LIB.
Usted solo tiene que reunir todas las definiciones de sus macros en un
archivo y almacenar el archivo en disco:
Macro1 MACRO
....
ENDM
Macro2 MACRO
....
ENDM
Para usar cualquiera de las macros catalogadas, en lugar de codificar
las definiciones MACRO al inicio del programa utilice la directiva
INCLUDE así:
INCLUDE C: MACRO.LIB
Macro1
Macro2
El ensamblador accesa el archivo llamado MACRO en la unidad C e
incluye ambas definiciones de macro, Macro1 y Macro2, en el
programa. El listado ensamblado contendrá una copia de las
definiciones de las macros.
La Directiva PURGE.
La ejecución de una instrucción INCLUDE hace que el ensamblador
incluya todas las definiciones de macros que están especificadas en la
biblioteca. Sin embargo, suponga que una biblioteca contiene las
macros SUMA, RESTA, DIVIDE, pero que el programa solo necesita
SUMA. La directiva PURGE permite que usted "elimine" la macros
RESTA y DIVIDE que no necesita del ensamblado actual:
IF1
INCLUDE C:\MACRO.LIB
ENDIF
PURGE RESTA, DIVIDE
necesarias
;Incluye la biblioteca completa
;Elimina la macros no
Una operación PURGE facilita solo el ensamblado de un programa y
no tiene efecto sobre las macros almacenadas en la biblioteca.
3.3.1 Internas.
3.3.2 Externas.
3.4 Procedimientos.
Definición de procedimientos
Un procedimiento es un conjunto de instrucciones que tienen la finalidad de
ejecutar una tarea especifica dentro de un programa. Los procedimientos son
muy similares a las macros.
Un procedimiento se declara una sola vez en el código fuente y cuando el
programa se ensambla y ejecuta, el procedimiento se coloca en memoria para
que pueda ser utilizado por el programa.
Las principales ventajas en el uso de procedimientos son: permiten una
codificación más limpia y compacta, es decir el código fuente es más pequeño;
también permiten el ahorro de memoria, esto es porque un mismo
procedimiento puede ser llamado varias veces en el mismo programa y sólo
requiere memoria una vez.
Los procedimientos tienen la desventaja de que reducen la velocidad de
ejecución de los programas, esto se debe a la forma en que los procedimientos
se ejecutan. A continuación se presentan los pasos necesarios para ejecutar un
procedimiento:
1.- Se encuentra la llamada Call
2.- El microprocesador almacena en la Pila el contenido del IP
3.- Se coloca en el IP el valor del desplazamiento correspondiente al
Procedimiento
4.- El microprocesador ejecuta las instrucciones del procedimiento
5.- El procedimiento termina cuando se encuentra la instrucción Ret
6.- Se saca de la pila el valor original del IP y se continua el flujo del programa
Un procedimiento se declara de la siguiente forma:
PROC nombre
instrucción
instrucción
....
RET
ENDP NOMBRE
En donde PROC es una palabra reservada que indica el inicio de un
procedimiento, RET es una instrucción que indica la terminación del conjunto
de instrucciones de un procedimiento y finalmente ENDP es la palabra
reservada para fin de procedimiento.
Paso de parámetros
Los procedimientos en lenguaje ensamblador no cuentan con un mecanismo
para el paso de parámetros; por lo cual, la única forma de lograr esto es
colocando los parámetros que nos interesan en los registros de propósito
general antes de que el procedimiento sea ejecutado.
El siguiente procedimiento coloca el cursor en las coordenadas establecidas en
Dl y Dh.
Proc GotoXY
xor bh,bh
mov ah,02h
int 10h
Ret
Endp GotoXY
En este ejemplo, las coordenadas XY se deben situar en el registro DX antes
de que se llame al procedimiento.
Llamada a procedimientos
Los procedimientos son llamados por los programas por medio de la instrucción
CALL, seguida del nombre del procedimiento.
Ejemplo:
Call GotoXY
El siguiente programa muestra la forma de pasarle parámetros a los
procedimientos por medio de los registros generales. Este programa declara
tres procedimientos:
GotoXY: Coloca el cursor en las coordenadas especificadas
Limpia_Pantalla: Limpia la pantalla
Imprime_Cad: Imprime una cadena en la posición actual del cursor
.COMMENT
*
Programa: Proc2.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra la forma de utilizar procedimientos en los
programas por medio de la instrucción Call y la forma de pasarles parámetros.
.MODEL TINY
.DATA
Cad1 db 'Esta es una cadena de prueba...',13,10,'$'
.CODE
INICIO: ;Punto de entrada al programa
Mov DL,20 ;X=20
Mov DH,10 ;Y=10
Call Gotoxy ;GotoXY 20,10
Lea DX,cad1 ;DX->Cad1
Call Imprime_Cad ;Imprimir Cad1
Mov Ax,04C00h ;Terminar y regresar al dos
Int 21h ;
END INICIO
;*********************************************************************
;Procedimiento: GotoXY
;Descripción: Coloca el cursor una posición especifica de la pantalla
;Parámetros: Dl=X, Dh=Y
;*********************************************************************
PROC GotoXY
Xor Bh,Bh
Mov Ah,02h
Int 10h
Ret
ENDP GotoXY
;***********************************************************************
;Procedimiento: Limpia_Pantalla
;Descripción: Imprime una cadena de caracteres en la posición del cursor
;Parámetros: La dirección de la cadena en DX
;***********************************************************************
PROC Imprime_Cad
Mov Ah,09h
Int 21h
Ret
ENDP Imprime_Cad
END
http://www.monografias.com/trabajos11/lenen/lenen2.s
html
El segmento de código contiene el código ejecutable de un programa.
También tiene uno o mas procedimientos, definidos con la directiva
PROC. Un segmento que tiene solo un procedimiento puede aparecer
como sigue:
NOMBRE
nomsegmento
nomproc
nomproc
nomsegmento
OPERACION
SEGMENT
PROC
.
.
.
ENDP
ENDS
OPERANDO
PARA
FAR
COMENTARIO
;Un
;procedimiento
;dentro
;del segmento
;de código
El nombre del procedimiento debe estar presente, ser único y seguir
las reglas para la formación de nombres del lenguaje. El operando far
en este caso esta relacionado con la ejecución del programa. Cuando
usted solicita la ejecución de un programa, el cargador de programas
del DOS utiliza este nombre de procedimiento como el punto de
entrada para la primera instrucción a ejecutar.
La directiva ENDP indica el fin de un procedimiento y contiene el
mismo nombre que el enunciado PROC para permitir que el
ensamblador relacione a los dos. Ya que los procedimientos deben
estar por completo dentro de un segmento, ENDP define el final de un
procedimiento antes que ENDS defina el final de un segmento.
LLAMADA DE PROCEDIMIENTOS.
Hasta ahora los segmentos de código han consistido solo en un
procedimiento, codificado como:
BEGIN PROC FAR
.
.
.
BEGIN ENDP
En este caso el operador FAR informa al sistema que la dirección
indicada es el punto de entrada para la ejecución del programa,
mientras que la directiva ENDP define el final del procedimiento. Sin
embargo, un segmento de código puede tener cualquier numero de
procedimientos, todos distinguidos por PROC y ENDP. Un
procedimiento llamado (o subrutina) es una sección de código que
realiza una tarea definida y clara (tal como ubicar el cursor o bien
obtener entrada del teclado).
La organización de un programa en procedimientos proporciona los
beneficios siguientes:
1. Reduce la cantidad de código, ya que un procedimiento común
puede ser llamado desde cualquier lugar en el segmento de código.
2. Fortalece la mejor organización del programa.
3. Facilita la depuración del programa, ya que los errores pueden ser
aislados con mayor claridad.
4. Ayuda en el mantenimiento progresivo de programas, ya que los
procedimientos son identificados de forma rápida para su
modificación.
Operaciones CALL y RET
La instrucción CALL transfiere el control a un procedimiento llamado, y
la instrucción RET regresa del procedimiento llamado al procedimiento
original que hizo la llamada. RET debe ser la ultima instrucción en un
procedimiento llamado. Los formatos generales para CALL y RET son:
El código objeto particular que CALL y RET generan depende de si la
operación implica un procedimiento NEAR (cercano) o un
procedimiento FAR (lejano).
Llamada y regreso cercanos. Una llamada (CALL) a un
procedimiento dentro del mismo segmento es cercana y realiza lo
siguiente:



Disminuye el SP en 2 (una palabra)
Mete el IP (que contiene el desplazamiento de la instrucción que
sigue al CALL) en la pila.
Inserta la dirección del desplazamiento del procedimiento
llamado en el IP (esta operación vacía el resultado de la
instrucción previamente procesada),
Un RET que regresa desde un procedimiento cercano realiza lo
siguiente:


Saca el antiguo valor de IP de la pila y lo envía al IP (lo cual
también vacía el resultado de la instrucción previamente
procesada).
Incrementa el SP en 2.
Ahora el CS:IP apunta a la instrucción que sigue al CALL original en la
llamada del procedimiento, en donde se reasume la ejecución.
Llamada y regreso lejanos. Una llamada (CALL) lejana llama a un
procedimiento etiquetado con FAR, tal vez en un segmento de código
separado. Un CALL lejano mete a la pila al CS y al IP, y RET los saca
de la pila.
page 60,132
TITLE P08CALLP (EXE) Llamada a procedimientos
.MODEL SMALL
.STACK
64
.DATA
;--------------------------------------------------------------------.CODE
BEGIN PROC
FAR
CALL
B10
;Llama a B10
;
...
MOV
AX,4C00H ;Salida a DOS
INT 21H
BEGIN ENDP
;--------------------------------------------------------------------B10
PROC
NEAR
CALL
C10
;Llama a C10
;
...
RET
;De regreso
B10
ENDP
;Quien llama
;--------------------------------------------------------------------END BEGIN
3.4.1 Internos.
Procedimientos internos
Los procedimientos internos son aquellos que se declaran y se llaman dentro del mismo
programa, también son llamados procedimientos locales.
El listado anterior muestra la forma de utilizar procedimientos internos.
3.4.2 Externos.
Procedimientos externos
Los procedimientos externos, a diferencia de los internos, se declaran en
módulos o programas separados al programa donde el procedimiento es
llamado, en otras palabras, la llamada al procedimiento se encuentra en un
programa y el procedimiento en otro.
Para poder utilizar procedimientos externos, es necesario que sean declarados
como públicos en el programa donde se encuentran y que sean llamados como
externos en el programa donde serán usados. Para lograr esto, Pass32 cuenta
con tres directivas de ensamble: .PUBLIC para declarar los procedimientos
como públicos, .EXTERN para indicar que el procedimiento que se va a usar
está fuera del programa y .INCLUDE para enlazar el programa que contiene los
procedimientos con el programa que los llama.
El siguiente programa muestra el uso de las directivas de inclusión.
Primeramente, el archivo Proc2.ASM se modificó para que su variable Cad1
fuera declarada como publica, el programa Proc3.ASM contiene la línea
.INCLUDE Proc2.ASM, lo cual indica al ensamblador que, en caso de que se
soliciten datos, etiquetas o procedimientos externos, éstos se busquen en el
archivo incluido.
Pass32 proporciona grandes facilidades para el manejo de procedimientos; en
este caso, solamente Cad1 debe ser declarada como pública, puesto que los
procedimientos se buscan y anexan automáticamente al programa que los
llama si es que existen.
.COMMENT
*
Programa: Proc3.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra la forma de utilizar procedimientos y datos
externos en los programas por medio de las directivas de inclusión include y
public.
.MODEL TINY
.INCLUDE proc2.ASM ;Incluir el archivo proc2.asm
;el cual contiene la variable de cadena
;Cad1 y los procedimientos externos
;usados en este programa.
.DATA
Cad2 db 'Esta es una cadena de prueba 2...',13,10,'$'
.CODE
INICIO: ;Punto de entrada al programa
Mov Dl,20 ;X=20
Mov Dh,10 ;Y=10
Call GotoXY ;GotoXY 20,10
Lea DX,Cad2 ;DX->Cad2 en Proc3.asm
Call Imprime_Cad ;Imprime Cad2
Lea DX,Cad1 ;DX->Cad1 en Proc2.asm
Call Imprime_Cad ;Imprime Cad1
Mov AX,04C00h ;Fin del programa
Int 21h ;
END INICIO
END
.COMMENT
*
Programa: Proc2.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra la forma de utilizar procedimientos en los
programas por medio de la instrucción Call y la forma de pasarles parámetros.
.MODEL TINY
.DATA
.PUBLIC Cad1 db 'Esta es una cadena de prueba...',13,10,'$'
.CODE
INICIO: ;Punto de entrada al programa
Mov DL,20 ;X=20
Mov DH,10 ;Y=10
Call Gotoxy ;GotoXY 20,10
Lea DX,cad1 ;DX->Cad1
Call Imprime_Cad ;Imprimir Cad1
Mov Ax,04C00h ;Terminar y regresar al dos
Int 21h ;
END INICIO
;*********************************************************************
;Procedimiento: GotoXY
;Descripción: Coloca el cursor una posición especifica de la pantalla
;Parámetros: Dl=X, Dh=Y
;*********************************************************************
PROC GotoXY
Xor Bh,Bh
Mov Ah,02h
Int 10h
Ret
ENDP GotoXY
;***********************************************************************
;Procedimiento: Limpia_Pantalla
;Descripción: Imprime una cadena de caracteres en la posición del cursor
;Parámetros: La dirección de la cadena en DX
;***********************************************************************
PROC Imprime_Cad
Mov Ah,09h
Int 21h
Ret
ENDP Imprime_Cad
END
Con estas capacidades, es fácil crear bibliotecas de procedimientos y macros
que puedan ser utilizados constantemente por los demás programas,
ahorrando con ello tiempo de programación al reutilizar código fuente.
El siguiente programa muestra la forma de escribir una biblioteca de
procedimientos y la forma de utilizarlos en los programas.
.COMMENT
*
Programa: Proc3.ASM
Autor: Juan Carlos Guzmán C.
Descripción: Este programa ilustra la forma de utilizar procedimientos y datos
externos en los programas por medio de las directivas de inclusión include y
public.
.MODEL TINY
.INCLUDE proclib.inc ;Incluir el archivo proclib.inc
;el cual contiene la variable de cadena
;Cad1 y los procedimientos externos
;usados en este programa.
.DATA
Cad1 db 'Esta es una cadena de prueba 2...',13,10,'$'
Cad2 db 'Presiona una tecla...','$'
.CODE
INICIO: ;Punto de entrada al programa
Call limpia_Pantalla ;
Mov Dl,20 ;X=20
Mov Dh,10 ;Y=10
Call GotoXY ;GotoXY 20,10
Lea DX,Cad1 ;DX->Cad1
Call Imprime_Cad ;Imprime Cad1
Mov Dl,40 ;
Mov Dh,24 ;
Call GotoXY ;GotoXY 40,25
Lea DX,Cad2 ;
Call Imprime_Cad ;Imprime Cad2
Call Espera_Tecla ;Esperar por una tecla presionada
Mov AX,04C00h ;Fin del programa
Int 21h ;
END INICIO
END
.COMMENT
Biblioteca de Procedimientos en Lenguaje ensamblador
.CODE
;*********************************************************************
;Procedimiento: GotoXY
; Descripción: Coloca el cursor una posición especifica de la pantalla
; Parámetros: Dl=X, Dh=Y
;*********************************************************************
PROC GotoXY
Xor Bh,Bh
Mov Ah,02h
Int 10h
Ret
ENDP GotoXY
;***********************************************************************
;Procedimiento: Imprime_Cad
; Descripción: Imprime una cadena de caracteres en la posición del cursor
; Parámetros: La dirección de la cadena en DX
;***********************************************************************
PROC Imprime_Cad
Int 21h
Ret
ENDP Imprime_Cad
;**********************************************************************
;Procedimiento: Limpia_Pantalla
; Descripción: Limpia la pantalla de la computadora y coloca el cursor
; en 0,0.
; Parámetros: Ninguno
;**********************************************************************
PROC Limpia_Pantalla
mov ax,0600h
mov bh,17h
mov cx,0000h
mov dx,184fh
int 10h
Mov dx,0000h
Call Gotoxy
Ret
ENDP Limpia_Pantalla
;**********************************************************************
;Procedimiento: Espera_Tecla
; Descripción: Detiene la ejecución de un programa hasta que se presiona
; una tecla
; Parámetros: Ninguno
;**********************************************************************
PROC Espera_Tecla
mov ah,10h
int 16h
Ret
ENDP Espera_Tecla
http://www.monografias.com/trabajos11/lenen/lenen2.s
html
Unidad 4. Programación híbrida.
Este tipo de programación se da cuando el programador necesita emplear
elementos que no estan contemplados dentro de los lenguajes de alto nivel que
habitualmente usa.
Por ejemplo, la mayor parte de los lenguajes de alto nivel, no soportan o no
incluyen instrucciones para el manejo del mouse, lápiz ópticos, adaptadores de
juegos, etc. Para solucionar este tipo de problemas, el programador tiene que
recurrir a la escritura de parches en lenguaje ensamblador, los cuales
actualmente son fáciles de implementar.
El problema mayor, que el programador enfrenta al establecer la interfaz entre
el lenguaje de alto nivel y el lenguaje ensamblador, es el de conectar realmente
los dos programas y pasar las variables de un lado a otro.
Afortunadamente, en la actualidad es muy sencillo realizar las interfaces entre
dos lenguajes, el siguiente objetivo nos muestra mediante ejemplos, la
interconexión entre el Lenguaje Pascal y el Lenguaje ensamblador.
El lenguaje Pascal, y en particular el Turbo Pascal, es el lenguaje de
programación más usado en la actualidad. Este lenguaje a partir de sus
versiones 6.0 tiene la ventaja de que los parches que se realizan en lenguaje
ensamblador, ya no sean fuera del código fuente del programa, sino que en el
mismo código se introduzcan las instrucciones en lenguaje ensamblador, las
cuales seran ensambladas al momento de la compilación.
4.6 Directivas para compilación híbrida.
4.7 Funciones en ensamblador.
4.8 Bloques en ensamblador.
4.9 Operadores.
4.10 Integrar módulos de ensamblador en lenguajes de
alto nivel.
Más información en el achivo:
leng_ensamblador.pdf
Documentos relacionados
Descargar