|
Cursos y Tutoriales Instrucciones de Salto. Vimos que en el funcionamiento de un microprocesador se reduce básicamente a los siguientes pasos: Recogida de la siguiente instrucción de la dirección CS:IP Incremento de IP en el número de bytes que componen la instrucción. Ejecución de la instrucción. Una introducción de salto se reduce a cambiar el contenido de IP y, eventualmente el de CS. Principalmente, existen dos tipos de instrucciones de salto: aquellas que especifican la dirección de salto inmediato después del cód. de operación, es decir, especifican la etiqueta a la que hay que saltar (denominados saltos directos), y aquellas que especifican una dirección de memoria de la que hay que recoger la dirección a la que saltar (denominadas saltos indirectos). Los bytes que componen una instrucción de salto directo incluyen en el cód. la operación algunos bytes que especifican la dirección a la que se debe producir el salto. Pero existen varios formatos posibles para la instrucciones de salto directo. El primero se denomina short jump (salto corto), y el único dato que incluye la instrucción después del cód. de operación es un byte, que representa en complemento a 2 el valor a añadir a IP para seguir la ejecución. Este byte se suma a IP, para lo que primero es necesario extenderlo en signo (que el signo del primer byte ocupe el segundo byte) a 16 bits. Así, el byte representa un desplazamiento entre -128 y +127 bytes (256 bytes), que es el rango que se puede especificar con un bytes en complemento a 2. Si observamos el orden en el que el microprocesador lleva a cabo la ejecución de una instrucción, veremos que el desplazamiento se suma a IP después de haber incrementado éste. Por tanto, el desplazamiento se toma desde la dirección de comienzo de la siguiente instrucción al salto, y no desde la propia instrucción de salto. El siguiente formato de salto directo es el near jump o salto cercano. Este formato, la instrucción incluye dos bytes que forman la palabra a sumar a IP, también en complemento a 2. Así, el rango de salto está entre -32768 y +32768 bytes (65535 bytes), que efectivamente permiten un salto a cualquier punto del segmento donde reside la instrucción de salto (en este formato CS tampoco es alterado por el salto). El ensamblador comprueba si el salto está en el rango (-128, +127) para realizar un salto corto y si no lo está genera un salto cercano. El último tipo de salto se denomina far jump o salto lejano. Esta denominación se debe a que éste formato de salto, cambia tanto CS como IP, pudiendo saltar a cualquier punto del megabyte direccionable (2 elevado a 20). En éste formato de salto, la instrucción lleva dos palabras con el desplazamiento y el segmento de la dirección a la que hay que saltar (se utiliza para realizar un salto a otro segmento). Este tipo de salto copia directamente en IP y CS los valores dados por la instrucción, sin tener en cuenta el contenido previo de ambos. Existen dos formatos de instrucciones de indirecto: el primero, denominado near jump o salto cercano, lee una palabra de la dirección de memoria especificada y carga el registro IP con ésta. Así, se puede saltar a cualquier punto del segmento donde resida la instrucción de salto. El otro tipo se denomina far jump o salto lejano, y toma de la dirección especificada dos palabras, la primera de la cuales se introduce en IP, y la segunda en CS (Ya que el ordenamiento INTEL siempre se almacenan primero los elementos de menor peso). De ésta forma se puede saltar a cualquier punto de la memoria direccionable con un salto indirecto. * JMP: El formato de la instrucción es JMP dirección. Provoca un salto incondicional, por lo que se utiliza para seguir la ejecución del programa en otro punto, que puede ser especificando una etiqueta (salto directo) o especificando una dirección (salto indirecto). Cuando incluimos instrucciones de salto en el programa, indicamos la dirección del destino, y en caso de que el salto necesite especificar un valor a sumar a IP, el ensamblador se encarga de calcular el desplazamiento desde el punto donde se ejecuta el salto. En una instrucción JMP; el propio ensamblador decide si debe generar un salto corto o lejano: en el caso de que el destino esté en el rango de un byte con signo, se genera un salto corto, en caso contrario, se genera un salto cercano. Ejemplo: ETIQUETA1: JMP continuar ETIQUETA2: JMP continuar CONTINUAR: Nota: Para los siguiente saltos, vamos a tener en cuenta significados de palabras inglesas que nos van a ayudar a definir el tipo de salto a realizar: (Equal=igual, Not=no, Greater=mayor, Less=menor, Above=superior, Below=inferior, Carry=acarreo, Zero=cero, Overflow=desbordamiento, Sign=signo, Parity=paridad) * JA: (Salto si superior). Es equivalente a JNBE (Salto si no inferior ni igual). El formato es: JA etiqueta si tanto el flag de acarreo CF como el flag de cero ZF está a cero (CF=0, ZF=0). Si CF=1 o ZF=1 no se transfiere el control. No se considera el signo. Ejemplo: CMP ax, bx ; Comparar AX con BX. JA etiqueta ; Saltar (Bifurcar) a ETIQUETA si AX>BX . ; (sin considerar signo). . ETIQUETA: * JAE: (Salto si superior o igual). Es equivalente a JNB (Salto si no inferior). El formato es: JAE etiqueta. Salta a la etiqueta si el flag de acarreo es cero (CF=0). No se considera el signo. Ejemplo: CMP ax, bx ; Comparamos AX con BX. JAE etiqueta ; Bifurca a ETIQUETA si AX> o =BX . ; (sin considerar el signo). . ETIQUETA: * JB: (Salto si inferior). Es equivalente a JNAE (Salto si no superior ni igual) y a JC (Salto sin acarreo). El formato es: JB etiqueta. Salta a la etiqueta si el flag de acarreo es uno (CF=1). No se considera el signo. Ejemplo: CMP ax, bx JB etiqueta ; Bifurca a ETIQUETA si AX < BX . ; (sin considerar el signo). . ETIQUETA: * JBE: (Salto si inferior o igual). Es equivalente a JNA (Salto si no superior). El formato es: JBE etiqueta. Salta a la etiqueta si el flag de acarreo es igual a 1 o el flag de cero es igual a uno (CF=1 y ZF=1). Si CF=0 y ZF=0 no hay salto. No se considera el signo. Ejemplo: CMP ax, bx JBE etiqueta ; Bifurca a ETIQUETA si AX es = o < que BX . ; (sin considerar el signo). . ETIQUETA: * JE: (Salto si igual). Es equivalente a JZ (Salto si cero). El formato es: JE etiqueta. Salta a la etiqueta si el flag de cero es igual a uno (ZF=1). Se considera número con signo y sin signo. Ejemplo: CMP ax, bx ; Comparo AX con BX. JE etiqueta1 ; Bifurca a ETIQUETA1 si AX = BX. CMP ax, bx ; AX=AX-BX * JG: (Salto si mayor). Es equivalente a JNLE (Salto si no menor ni igual). El formato es: JG etiqueta. Salta a la etiqueta si el flag de cero es igual a cero y el flag de desbordamiento contiene el mismo valor que el flag se signo (ZF=0 y SF=OF). Si ZF=1 o SF<>OF, no hay salto. Se considera el signo. Ejemplo: CMP ax, bx JG etiqueta ; Bifurca a ETIQUETA si AX > BX . ; (considerando el signo). ETIQUETA: * JGE: (Salto si mayor o igual). Es equivalente a JNL (Salto si no menor). El formato es: JGE etiqueta. Salta a la etiqueta si el flag de desbordamiento contiene el mismo valor que el flag de signo (SF=OF). Se considera el signo. Ejemplo: CMP ax, bx JGE etiqueta ; Bifurca a ETIQUETA si AX es > o = BX . ; (considerando el signo). ETIQUETA: Ejemplo: CMP ax, bx JLE etiqueta ; Bifurca a ETIQUETA si AX es < o = BX . ; (considerando el signo). . ETIQUETA: * JNA, JNAE, JNB, JNBE, JNE, JNG, JNGE, JNL, JNLE: Estas instrucciones comprueban exactamente las condiciones opuestas a sus análogas sin la letra N. En realidad no sería necesaria, porque son sinónimas de JBE, JB, JAE, JNZ, JLE, JL, JGE Y JE, respectivamente. Pero el lenguaje ensamblador estándar las incluye para facilitar el trabajo del programador. * JO: (Salto si desbordamiento). Formato es: JO etiqueta. Salta a la etiqueta si el flag de desbordamiento está a uno (OF=1). Ejemplo: ADD ax, bx ; AX=AX+BX JO etiqueta ; Bifurca a ETIQUETA si hay desbordamiento . ; (Overflow). ETIQUETA: * JNO: (Salto si no desbordamiento). El formato es: JNO etiqueta. Salta a la etiqueta si el flag de desbordamiento está a cero (OF=0). Ejemplo: ADD al, bl ; AL=AL+BL JNO etiqueta ; Bifurca a ETIQUETA si no hay desbordamiento . ; (No overflow). . ETIQUETA: * JS: (Salto si signo). El formato es: JS etiqueta. Salta a la etiqueta si el flag de signo está a uno (SF=1). Ejemplo: SUB ax, bx ; AX=AX-BX JS etiqueta ; Bifurca a ETIQUETA si signo, es decir, AX < 0 . ; (en este caso, si AX es menor que BX). . ETIQUETA: * JNS: (Salto si no signo / si el signo en positivo). El formato es: JNS etiqueta. Salta a la etiqueta si el flag de signo está a cero (SF=0). Ejemplo: SUB ax, bx ; AX=AX-BX JNS etiqueta ; Bifurca a ETIQUETA si no signo, es decir, AX > o = que BX . ; (en este caso, si AX es mayor o igual que BX). . * JP: (Salto si paridad). Es equivalente a JPE (salto sin paridad par). El formato es: JP etiqueta. Salta a la etiqueta si el flag de paridad está a uno (PF=1). Ejemplo: AND ax, bx ; AX=AX AND BX JP etiqueta ; Bifurca a ETIQUETA si paridad par, es decir . ; si el número de "unos (1)" que hay en AX es par. . ETIQUETA: * JNP: (Salto si no paridad). Es equivalente a JPO (salto sin paridad impar). El formato es: JNP etiqueta. Salta a la etiqueta si el flag de paridad está a cero PF=0). Ejemplo: AND ax, bx ; AX=AX AND BX JNP etiqueta ; Bifurca a ETIQUETA si paridad impar, es decir . ; si el número de "unos (1)" que hay en AX es impar. . ETIQUETA: * LOOP: Esta instrucción permite realizar "bucles" utilizando el registro CX como contador (CX en un contador que va decrementándose). Un bucle es un conjunto de instrucciones que se ejecutan una serie de veces. Esta instrucción equivale al par: DEC CX // JNZ etiqueta. El formato es: LOOP etiqueta. Ejemplo: MOV cx, 15 ; CX=15; 15 sería el número de veces que se va a ejecutar el bucle. ETIQUETA: ; Aquí estarían las instrucciones que están dentro del bucle. LOOP etiqueta ; CX=CX-1 y bifurca a ETIQUETA si CX es distinto a cero. * LOOPE: Esta instrucción al igual que LOOP, permite realizar "bucles" utilizando el registro CX como contador (CX en un contador que va decrementándose) pero además el flag de cero debe estar a uno (ZF=1). Es equivalente a LOOPZ (Bucle si cero). Esta instrucción equivale al par: JNE FIN // LOOP OTRO. El formato es: LOOPE etiqueta. Ejemplo: MOV cx, Length tabla ; CX=longitud de la TABLA. MOV si, inicio ; Movemos a SI el inicio de la TABLA. DEC si ; Esto se hace para poder realizar el bucle ; que viene ahora OTRO: INC si ; Movemos a SI su valor inicial. CMP tabla[SI], 0 ; Comparamos cada valor de la TABLA con cero LOOPE OTRO ; si el valor de TABLA es igual a cero realiza un ; LOOP normal, sino, no hace el LOOP. * LOOPNE: Esta instrucción al igual que LOOP, permite realizar "bucles" utilizando el registro CX como contador (CX en un contador que va decrementándose) pero además el flag de cero debe estar a cero (ZF=0). Es equivalente a LOOPNZ (Bucle si no cero). Esta instrucción equivale al par: JE FIN // LOOP OTRO. El formato es: LOOPNE etiqueta. Ejemplo: MOV cx, Length tabla ; CX=longitud de la TABLA. MOV si, inicio ; Movemos a SI el inicio de la TABLA. DEC si ; Esto se hace para poder realizar el bucle ; que viene ahora. OTRO: INC si ; Movemos a SI su valor inicial. CMP tabla[SI], 0 ; Comparamos cada valor de la TABLA con cero LOOPNE OTRO ; si el valor de TABLA es distinto a LOOP normal, ; sino, no hace el LOOP. Instrucciones de Rotación y Traslación. Este grupo de instrucciones nos permitirán tratar la información almacenada en registros o en memoria mediante el tratamiento unitario de sus bits. * RCL: (Rotar a la izquierda con acarreo). El formato es: RCL operando, contador. Rota a la izquierda los bits del operando junto con la bandera de acarreo, CF, el número de bits especificado en el segundo operando. Si el número a desplazar es 1, se puede especificar directamente (Por ejemplo: RCL AL, 1). Si es mayor que 1, su valor debe cargarse en CL y especificar CL como segundo operando. Ejemplo: MOV cl, 3 ; Rotar 3 bits ; AL = 0101 1110b, CF=0 (Flag de acarreo=0) RCL al, cl ; AL = 1111 0001b, CF=0 Procedimiento:
* RCR: (Rotar a la derecha con acarreo). Ejemplo: MOV cl, 3 ; Rotar 3 bits ; AL = 0101 1110b, CF=0 (Flag de acarreo=0) RCR al, cl ; AL = 1000 1011b, CF=1 Procedimiento:
* ROR: (Rotar a la derecha). El formato es: ROR operando, contador. Rota a la derecha los bits del operando de tal forma que el bits del extremo derecho del operando destino para al bit extremo izquierdo de dicho operando y al mismo tiempo para el bit de acarreo (CF). Si el número a desplazar es 1, se puede especificar directamente (Por ejemplo: ROR AL, 1). Si es mayor que 1, su valor debe cargarse en CL y especificar CL como segundo operando. ; AL = 0011 0011b, CF=0 (Flag de acarreo=0) RCR al, cl ; AL = 1100 1100b, CF=1 Procedimiento:
* ROL: (Rotar a la izquierda). El formato es: ROL operando, contador. Rota a la izquierda los bits del operando de tal forma que el bits del extremo izquierdo del operando destino para al bit extremo derecho de dicho operando y al mismo tiempo para el bit de acarreo (CF). Si el número a desplazar es 1, se puede especificar directamente (Por ejemplo: ROL AL, 1). Si es mayor que 1, su valor debe cargarse en CL y especificar CL como segundo operando. Ejemplo: MOV cl, 2 ; Rotar 2 bits ; AL = 1100 1100b, CF=0 (Flag de acarreo=0) RCR al, cl ; AL = 0011 0011b, CF=1 Procedimiento:
* SAL: (Desplazamiento aritmético a la izquierda). Es equivalente a SHL (Desplazamiento lógico a la izquierda). El formato es: SAL operando, contador. SHL y SAL realizan la misma operación y son físicamente la misma instrucción. Copia en cada bit del operando el contenido previo del bit de su derecha. El bit de menor peso se pone a cero. El contenido previo del bit de mayor peso se copia en el flag de acarreo (CF). Es equivalente a multiplicar el operando por dos, tanto para números sin signo como para número en complemento a 2, siempre el resultado no se salga del rango. Si el número de bits a desplazar es 1, se puede especificar directamente (Por ejemplo: SAL AL, 1). Si es mayor que 1, su valor debe cargarse en CL y especificar CL como segundo operando. Ejemplo: MOV cl, 2 ; Desplazar 2 bits ; AL = 1100 1100b, CF=0 (Flag de acarreo=0) SAL al, cl ; AL = 0011 0000b, CF=1 Procedimiento:
Ejemplo: MOV cl, 2 ; Desplazar 2 bits ; AL = 1100 1100b, CF=0 (Flag de acarreo=0) SAR al, cl ; AL = 1111 0011b, CF=0 Procedimiento:
* SHR: (Desplazamiento aritmético hacia la derecha). El formato es: SAR operando, contador. Copia en cada bit del operando el contenido previo del bit de la izquierda. En el bit de mayor peso se almacena un 0. El contenido previo del bit de menor peso se copia en el flag de acarreo (CF). Es equivalente a dividir el operando por dos para números sin signo. Si el número de bits a desplazar es 1, se puede especificar directamente (Por ejemplo: SHR AL, 1). Si es mayor que 1, su valor debe cargarse en CL y especificar CL como segundo operando. Ejemplo: MOV cl, 2 ; Desplazar 2 bits ; AL = 0011 0011b, CF=0 (Flag de acarreo=0) SHR al, cl ; AL = 0000 1100b, CF=1 Procedimiento:
Ejercicios: 1.- Disponemos en memoria de una variable que nos ocupa una palabra, identificada con el símbolo UNO y que tiene el valor de 35 (dentro del segmento de datos: UNO DW 35), y disponemos de un byte identificado con el símbolo DOS y que posee un valor de 10 (dentro del segmento datos: DOS DB 10). Calcular la suma de estos datos. 2.- Acceder a un datos que está almacenado en la dirección 123Ah:0008 en una palabra de memoria dentro del segmento extra, y calcular lo siguiente: a) Si los bits: 11, 9, 5 y 3 están a uno. b) El número de bits a uno que tiene ese dato. c) Si este dato es de paridad impar, debe saltar a una etiquea que se llama FIN. 3.- Supongamos que tenemos cargados en variables de memoria (UNO, DOS, TRES, CUATRO, CINCO, SEIS, SIETE de tipo byte), siete informaciones de ficheros que hemos leido de un disco. Cada información puede tener, en sus cuatro bits menos signifactivos, los siguientes atributos: Si bit 3 a 1 - Atributo de Lectura. Si bit 2 a 1 - Atributo de Sistema. Si bit 1 a 1 - Fichero Oculto. Si bit 0 a 1 - Fichero Borrado. Se quiere saber cuantos ficheros de estos siete son: de lectura, de sistema, ocultos, borrados, de lectura y sistema, de lectura y oculto, de sistema y oculto y de lectura y sistema y oculto. UNO DB 1111 0111 DOS DB 1111 1000 TRES DB 1111 0101 CINCO DB 1111 1111 SEIS DB 1111 0010 SIETE DB 1111 1110 4.- Realiza una rutina que nos permita multiplicar dos cantidades que estén almacenadas en dos palabras de memoria, que conocemos con los simbolos UNO y DOS, considerando que dicha multiplicación debe realizarse mediante sumas sucesivas. 5.- Realizar una rutina que nos permita realizar la división de dos cantidades numéricas almacenadas en 2 dirección de memoria que vamos a conocer con los nombres UNO y DOS, considerando que dicha división se debe realizar mediante resta sucesivas. 6.- Disponemos de una cantidad almacenada en memoria identificada por 1 palabra mediante el símbolo UNO. Calcula el factorial del valor de la palabra. La Pila. La estructura de una PILA es similar a un montón de libros apilados: los elementos se van ordenando cada uno detrás del último en llegar (es decir, los libros se van apilando cada uno encima del anterio), pero al sacarlos de la estructura se empieza por el último en llegar, acabando por el primero (al retirar los libros se comienza por el superior, y se acaba por el que queda abajo del todo). A la operación de introducir un elemento en una pila se le suele dar el nombre de empujar un elemento (push en inglés). La operación de extraer un elemento de una pila se le denomina pop. Los elementos que puede almacenar la pila del microprocesador son valores de 16 bits, con lo cual el puntero de pila se debe incrementar o decrementar 2 unidades a la hora de sacar o introducir valores en la pila (a meter un valor de 16 bits en la pila el puntero de la pila se decrementa en dos unidades, y a la hora de sacar un elemento de la pila el puntero se incrementa en dos unidades; la pila crece hacia abajo en lugar de hacia arriba). El microprocesador tiene dos registros que se utilizan para gestionar la pila: el SS (Segmento de Pila) y el SP (Puntero de Pila). El par SS:SP da la dirección donde se encuentra el último valor empujado en la pila. * PUSH: Decrementa en 2 unidades el puntero de la pila, es decir, decrementa en 2 unidades el registro SP, y a continuación almacena en la cima de la pila la palabra especificada en el operando origen asociado a la instrucción. Formato PUSH origen Ejemplo: PUSH ax ;es equivalente a: SP = SP-2 // MOV ss:[sp], ax El operando origen no puede ser un operando inmediato (ni el registro de segmento CS). * POP: Esta instrucción toma una palabra de la cima de la pila y la sitúen el operando destino asociado a la instrucción, incrementando, a continuación, en 2 unidades el puntero de la pila. Formato POP origen Ejemplo: POP ax ; es equivalente a: AX = SS:[SP] // SP = SP + 2 Cuando una instrucción PUSH o POP se ejecuta en un código de programa con el tamaño de registro de 32 bits (USE32), el ensamblador utiliza como valor de trasferecencia 4 bits en lugar de 2 bytes (una palabra), y las operaciones realizadas con ESP se efectúan sobre unidades de 4 elementos. * PUSHF: Esta instrucción decrementa en 2 unidades el puntero de la pila y a continuación, almacena en la cima de la pila el registro de indicadores (FLAGS). No tiene ningún operando. * POPF: Esta instrucción almacena en el registro de indicadores (FLAGS) la palabra situada en la cima de la pila aumentando en 2 unidades, a continuación, el puntero de la pila. No tiene ningún operando. * PUSHA y POPA: Estas instruciones almacenan y sacan de la pila la información contenida en los registros siguientes y en el orden siguiente: AX, CX, DX, BX, SP, BP, SI y DI. El valor de SP es guardado en la pila antes de que el primer registro sea guardado. En el caso de utilizar registros de 32 bits la instrucciones serían: PUSHAD y POPAD. Todo lo que entra en la pila, tiene que salir de la pila. El orden de situar y sacar palabras de la pila es el siguiente: PUSH ax PUSH bx PUSH cx PUSH dx Rutina del programa POP dx POP cx POP bx POP ax Ejercicios: 1.- Se pide calcular los números comprendidos entre dos cantidades numéricas almacenados en palabras y que vamos a identificar con los símbolos UNO y DOS. Se debe utilizar de forma obligatoria instrucciones que manejen la pila. Interrupciones. Una interrupción es una señal que provoca la suspensión del programa que se estaba ejecutando y provoca el comienzo de ejecución de un programa de tratamiento que de solución a esa interrupción. A ese programa se le conoce como RUTINA DE TRATAMIENTO de esa interrupción. Este procesador nos presenta tres grupos de interrupciones: a) Interrupciones Hardware o Interrupciones Externas, que son aquellas provocadas por los dispositivos periféricos, controladas por un procesador especial de interrupciones (8259) o IPC (Controlador de Interrupciones Programable), y la rutina de tratamiento está "cableada". b)Interrupciones Internas, que son aquellas provocadas dentro del propio procesador por una situación anormal de funcionamiento de alguna de sus partes. C) Interrupciones de Software, Son aquellas que son programables y que podemos cambiar. Las interrupciones de software podemos llegar a manejarlas y por ello el ensamblador nos proporciona una instrucción que nos permita poner en funcionamiento una determinada rutina de interrupción; esta instrucción es INT. * INT. Formato INT núm_entero. Ese "núm_entero", asociado a la instrucción, es un identificativo que nos dice mediante la aplicación de un algoritmo, la posición de Memoria Interna donde se encuentra almacenada la dirección de comienzo de la rutina de tratamiento de esa interrupción. El ensamblador permite, normalmente, identificar 256 interrupciones. Una parte de ellas son las correspondientes a la ROM-BIOS y las proporciona el fabricante. Otra parte de ellas forman del sistema operativo DOS, y otra parte de ellas queda libre para que el programador genere sus propias rutinas de interrupción. Las interrupciones correspondientes a la parte de la BIOS y las correspondientes a la parte del DOS representas características similares. Existe un flag denominado IF (Interrupción Flag, Flaf de Interrupción) que determina la reacción del microprocesador ante una interrpción. Si el flag está a uno, el rpocesador responde a la interrupción producida; pero si el flag IF está a cero, la petición de interrupción será ignorada completamente por el microprocesador. En algunas secciones de código, resulta necesario deshabilitar las interrupciones (poner el flag IF a cero) durante algunos ciclos, y habilitarlas de nuevo después. La familia 8086 provee dos instrucciones que realizan estas tareas: STI (Activar flag de interrupciones): Pone el flag IF a i, de forma que se premiten las interrupciones. CLI (Borrar flag de interrupciones): Pone el flag IF a 0, de modo que el microprocesador no responde a más interrupciones hasta que se ejecuta un STI o se altera el contenido de los flags (entre ellos el de IF) recuperándolos de la pila con POPF o IRET. MOV ax, 8000h CLI MOV ss, ax MOV sp, 2000h STI * IRET: Retorno de interrupción. Formato: IRET (no tiene operandos). Retorna de una rutina de servicio a la interrupción, extrayendo de la pila los nuevos valores de IP y CS, en este orden, y el contenido del registro de flags. La ejecución continúa en la instrupción siguiente a la que se estaba ejecutando cuando ocurrió la interrupción. Ejemplos de interrupciones del DOS. Vamos a ver unos ejemplos de interrupciones del DOS (Vamos a ver unas interrupciones donde el "nº entero" va a ser 21h. Esta interrupción presenta una gran cantidad de funciones diversas; por ello además de indicar el "nº entero", debemos indicar también el "nº función" que deseamos dentro de esa interrupción. Dicho número se almacena siempre el registro AH): - INT 21h. Función 01h: Permite dar entrada a un carácter e teclado y al mismo tiempo dicho carácter aparece en pantalla, en la posición en la que se encuentre el cursor. El carácter tecleado queda almacenado en AL. Si no hay ningún carácter disponible, se espera hasta que haya alguno. MOV ah, 01h INT 21h ; El carácter tecleado queda en AL - INT 21h. Función 02h: Permite llevar un carácter desde el pocesador hacia la pantalla. Dicho carácter debe estar almacenado en el registro DL. Aparecerá en la posición donde se encuentre el cursor. MOV dl, carácter MOV ah, 02h INT 21h - INT 21h. Función 08h: Permite dar una entrada de un carácter desde el teclado pero sin que aparezca en pantalla. El carácter tecleado queda almacenado en el registro Al. Si no hay un carácter disponible se espera hasta que lo haya. MOV ah, 08h INT 21h ; El carácter tecleado queda en AL - INT 21h. Función 09h: Visualización de una cadena de caracteres. Nos permite llevar una cadena de caracteres hacia la pantalla. Dicha cadena aparecerá a partir de la posición en la que se encuentre el cursor. Esta función necesita que en el registro DX se encuentre la dirección de comienzo de la cadena a presentar en pantalla. MOV dx, offset cadena ; En DX queda el desplazamiento que hay que hacer dentro ; de DS para llegar a la posición donde se encuentra ; "cadena" (DS:DX). MOV ah, 08h INT 21h - INT 21h. Función 4Ch: Acabar el proceso con código de retorno. Permite realizar el retorno al Sistema Operativo. Acaba el proceso actual, enviando un código de retorno al programa original. Se trata de uno de los diversos métodos con los que se puede provocar una salida definitiva de un programa. MOV ah, 4ch INT 21h Otras instrucciones * LEA: Formato: LEA destino, fuente. Transfiere el desplazamiento del operando fuente al operando destino. El operando fuente debe ser un operando de memoria. El operando destino es un registro, pero no un registro de segmento. LEA permite especificar regitros índices en el operando fuente, al contrario que con la instrucción OFFSET. Ejemplo: LEA dx, [bx+si+20] ; En DX quedaría el desplazamiento que habría ;que hacer dentro del segmento de datos (DS), para ; acceder a la información ; indicada por la suma de BX + SI + 20. ; DX - BX + SI + 20 ; DS : DX = BX + SI + 20 (Segmento de Datos) TEXTO db "ejemplo1$" (Segmento de Código) LEA dx, texto ; Queda en DX el desplazamiento que hay que hacer dentro del ; segmento de datos (DS), para acceder a la información que tiene ; la variable TEXTO DS:DX= dirección del texto. Si situamos todos los datos que emplea nuestro programa en un sólo segmento, apuntando por DS, la localización de memoria de un dato se puede dar por un desplazamiento (offset), suponiendo implícitamente que reside en el segmento apuntando por DS. Pero si queremos especificar la dirección donde reside un dato que puede estar en cualquier lugar del megabyte direccionable, es necesario especificar tanto segmento donde se encuentra el dato como el desplazamiento dentro de dicho segmento; este tipo de punteros se denominan FAR POINTERS (Punteros lejanos). Cuando almacenamos un puntero cercano en memoria, se almacena únicamente una palabra. Pero cuando alamacenamos un puntero lejano, se almacena el desplazamiento y el segmente en palabras consecutivas en memoria. Al cargar un puntero cercano, por ejemplo, SI, se carga directamente de memoria con instrucciones como MOV SI, mem, de manera que el par DS:SI contiene el puntero deseado. Pero al cargar un puntero lejano, es necesario cargar tanto un registro con el desplazamiento (offest) como un registro de segmento del puntero (habitualmente se carga en ES, manteniendo DS siempre constante apuntando a los datos de uso habitual del programa). Existen 2 instrucciones que cargan de una sola vez tanto el desplazamiento como el segmento: LDS y LES. LDS reg, mem LDS si, cs:[di+2] LES reg, mem LES ax, [bp+si] Ambas instrucciones cargan en el registro especificado con reg la palabra contenida en la dirección dada por mem, y en el registro de segmento indicado (DS para LDS y ES para LES) la palabra contenida en la dirección indicada +2. * OFFSET: Formato OFFSET variable o OFFSET etiqueta. Podemos utilizar la instrucción OFFSET para obtener el desplazamiento dentro de un segmento de una etiqueta cualquiera. Ejemplo: (Segmento de Datos) TABLA db 'ejemplo 1$' (Segmento de Código) MOV ax, offeset tabla ; En AX queda el desplazamiento que hay que hacer ; dentro del segmento por defecto en curso para ; acceder al contenido de TABLA. ; AX = desplazamiento de TABLA. Estructuras de programación. Directivas. * IF: Las instrucciones que empiezan por "IF" son directivas condicionales. Sirven para que el ensamblador incluya o no las sentencias que vienen a continuación, según se cumpla o no una determinada condición. El formato es: .IF condicional sentencias [ .ELSELF condición2 sentencias ] [ .ELSE sentencias ] .ENDIF Ejemplo: .IF cx == 20 MOVE dx, 20 .ELSE MOVE dx, 30 .ENDIF Algunos operadores utilizados para la comparaciones son: == Igual != Distinto (no igual) > Mayor >= Mayor Igual < Menor <= Menor Igual && AND Lógico ("y") || OR Lógico ("o") * FOR: Las instrucciones que empiezan por "FOR" son directivas de "ciclos". El formato es: FOR parámetro, <Lista de argumentos> ENDM Ejemplo: MOV ax, 0 FOR arg, <1,2,3,4,5,6,7,8,9,10> ADD ax, arg ENDM ; Esto lo que hace es sumar cada vez a AX el valor que ; aparece en la de argumentos. ; ( AX = AX + 1, AX = AX + 2, AX = AX + 3,...) * WHILE: Las instrucciones que empiezan por "WHILE" son directivas de "ciclos". El formato es: .WHILE condición sentencias .ENDW Ejemplo: (Segmento de Datos) buf1 BYTE "Esto es una cadena", '$' buf2 BYTE DUP (?) (Segmento de Código) XOR bx, bx .WHILE (but1[bx]!= '$') MOV al, buf1[bx] MOV buf2[bx], al INC bx .ENDW * REPEAT: Las instrucciones que empiezan por "REPEAT" son directivas de "ciclos". El formato es: .REPEAT sentencias .UNTIL condición Ejemplo: (Segmento de Datos) buffer BYTE 100 DUP (0) (Segmento de Código) XOR bx, bx .REPEAT MOV ah, 01h INT 21h MOV buffer[bx], al INC bx .UNTIL (al==13) ; En este caso la interrupción 21h con la función 01h deja en AL la tecla que se ha pulsado y la mete en "buffer". Si esta es ENTER (13) se sale del bucle, sino sigue en él. |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||