Subrutinas Uso de subrutinas: Frecuentemente la misma pieza de código debe escribirse varias veces en muchas partes diferentes de un programa. En vez de repetir el código cada vez que sea necesario, hay una ventaja obvia si las instrucciones comunes se escriben solamente una vez. Un conjunto de instrucciones comunes que pueden utilizarse en un programa muchas veces se denomina subrutina.
Subrutinas
Uso de subrutinas: Cada vez que la subrutina se utiliza en la parte del programa principal, una ramificación se ejecuta al comienzo de la subrutina. Después que la subrutina ha sido ejecutada, una ramificación se hace de nuevo al programa principal.
Uso de subrutinas: Programa principal
Llamado a Subrutina
Subrutina
Subrutinas Uso de subrutinas: Programa principal
Llamado a Subrutina
Llamado a Subrutina
j j+1
Subrutina
Subrutinas Uso de subrutinas: Los registros y las memorias son comunes para el programa principal y para la subrutina, i.e., se consideran variables globales. Ventaja: la comunicación de los parámetros entre el programa principal y la subrutina es simple y rápido. Desventaja: el programador puede olvidar que ciertos registros usados por en el programa principal no deben ser alterados en la subrutina, esto puede causar serios problemas y la detección de este error es difícil.
Subrutinas Ejemplo: Se desea hacer un programa que realice las siguientes operaciones: (0100) (0100) + 5 (0200) (0200) + 5 (0204) (0204) + 5
Subrutinas Ejemplo: Se desea hacer un programa que realice las siguientes operaciones: (0100) (0100) + 5 (0200) (0200) + 5 (0204) (0204) + 5 La mejor solución sería utilizando una subrutina que tenga como parámetro una dirección X y que realice la operación: (X) (X) + 5 El programa principal debe cargar correctamente el registro X y llamar a la subrutina tres veces.
Subrutinas Ejemplo: Se desea hacer un programa que realice las siguientes operaciones: (0100) (0100) + 5 (0200) (0200) + 5 (0204) (0204) + 5 Programa principal LOAD X,0100 CALL SUM5 LOAD X,0200 CALL SUM5 LOAD X,0204 CALL SUM5
Subrutina SUM5 LOAD A,(X) ADD 5 STORE (X),A RET
Subrutinas Ejemplo: Se desea hacer un programa que realice las siguientes operaciones: (0100) (0100) + 5 (0200) (0200) + 5 (0204) (0204) + 5 Programa principal LOAD X,0100 CALL SUM5 LOAD X,0200 CALL SUM5 LOAD X,0204 CALL SUM5
¿Qué pasa si el programa principal estaba usando A? Subrutina SUM5 LOAD A,(X) ADD 5 STORE (X),A RET
Subrutinas Ejemplo: Se desea hacer un programa que realice las siguientes operaciones: (0100) (0100) + 5 (0200) (0200) + 5 (0204) (0204) + 5 Programa principal LOAD X,0100 CALL SUM5 LOAD X,0200 CALL SUM5 LOAD X,0204 CALL SUM5
¿Qué pasa si el programa principal estaba usando A?
kaput!! Subrutina SUM5 LOAD A,(X) ADD 5 STORE (X),A RET
Subrutinas Ejemplo: Se desea hacer un programa que realice las siguientes operaciones: (0100) (0100) + 5 (0200) (0200) + 5 (0204) (0204) + 5 Programa principal LOAD X,0100 CALL SUM5 LOAD X,0200 CALL SUM5 LOAD X,0204 CALL SUM5
Solución: se usa la pila
Subrutina SUM5 PUSH A LOAD A,(X) ADD 5 STORE (X),A POP A RET
Subrutinas La Pila (stack): Existe una memoria direccionada por el registro SP (stack pointer). ¿Cómo se usa? Cada vez que se hace PUSH X:
(SP) X SP SP + 1 Cada vez que se hace POP X: SP SP - 1 X (SP)
(es posible hacer PUSH X y luego POP Y)
Interrupciones
El ciclo de una instrucción (sin interrupción)
Interrupciones
Diagrama de estado (sin interrupción)
Interrupciones Ejemplo sin interrupciones: un programa quiere leer datos del disco duro. 1. El programa solicita datos a la unidad de disco. 2. La unidad de disco recibe solicitud y posiciona el cabezal del disco en la posición deseada. 3. La unidad lee los datos. 4. La unidad verifica consistencia de los datos (checksum) 5. if OK (Envía los datos a la U) else GOTO 3 6. La U recibe datos y continúa su programa
11
22
33
44
55
6 6
tt
Interrupciones Ejemplo sin interrupciones: un programa quiere leer datos del disco duro.
U solicita datos
1
Unidad de disco lee y envía datos La U no hace nada
2
3
4
U recibe datos
5
6
t
Interrupciones Ejemplo con interrupciones: un programa quiere leer datos del disco duro. 1. El programa solicita datos a la unidad de disco. 2. La U no espera datos, hace otra cosa: por ejemplo ejecuta otro programa o continua ejecutando el mismo programa siempre que pueda prescindir de los datos solicitados. 3. La unidad de disco se encarga de leer los datos correctamente. Cuando los datos están listos la unidad de disco “interrumpe” a la U. 4. La U deja de hacer lo que está haciendo y atiende la interrupción, i.e., recibe los datos de la unidad de disco. t (U) t (unidad de disco)
Interrupciones Ejemplo con interrupciones: un programa quiere leer datos del disco duro. U solicita datos
U hace otra cosa
U recibe datos
1
2
4
3 Unidad de disco lee y envía datos
Ahorro de tiempo
t interrupción
Interrupciones La interrupción es el mecanismo mediante el cual otros módulos pueden interrumpir una secuencia normal de procesamiento. • Programa: por ejemplo división por cero • Temporizador: cuando se cumple un tiempo específico • E/S: cuando hay algo que comunicar • Hardware: cuando ocurre una falla
Interrupciones
El ciclo de una instrucción (con interrupción)
Interrupciones
Diagrama de estado (con interrupción)
Interrupciones Bus de direcciones A0
A12
A12
U
MREQ RD WR
D0
D7
Bus de datos D7
D0
D7
ROM
A11
D0
WR
RAM RD
RD
CE
CE
A0
A11
A0
A12 A11 : A0
Interrupciones Bus de direcciones A0
A12
U
INT
MREQ RD WR
IORQ D0
D7
Bus de datos D0
D7
I/O
ROM
RAM CE
CE
A11
A0
CE
decoder
Interrupciones Funcionamiento de las interrupciones (posibilidad 1):
1. El dispositivo I/O cuando necesita interrumpir solicita atención y envía una señal INT a la U. 2. La U termina su instrucción y envía un reconocimiento a quien interrumpe mediante la señal IORQ (I/O request). 3. El dispositivo envía por el bus de datos un byte y la U forma una dirección a partir de este byte. 4. La U salta a esta dirección y ejecuta el programa de atención a la interrupción. 5. La U finaliza esta rutina de interrupción y regresa a la dirección que estaba en el momento de la interrupción.
Interrupciones Funcionamiento de las interrupciones (posibilidad 2):
1. Igual 2. Igual 3. La U al saber que es el dispositivo X el que interrumpe lee el elemento X del “vector de interrupciones” ubicado en algún lugar de la memoria, a partir de este elemento calcula la dirección de memoria de la rutina de atención de la interrupción. 4. Igual 5. Igual
Interrupciones
Interrupciones Interrupciones múltiples:
1. Inhibición de interrupciones: • La U ignora las interrupciones cuando ya está procesando una interrupción. • Las interrupciones ocurridas quedan pendientes y se ejecutan en una determinada secuencia una vez que la U termine la primera interrupción.
Interrupciones
Interrupción múltiple (secuencial)
Interrupciones Interrupciones múltiples (cont):
2. Definición de prioridades • Interrupciones de baja prioridad pueden ser interrumpidas por interrupciones de mayor prioridad. • Cuando una interrupción de prioridad alta ha sido atendida, la U regresa a la interrupción previa.
Interrupciones
Interrupción múltiple (anidadas)
Interrupciones
Secuencia temporal de varias interrupciones
Arquitectura en pipeline • Los procesadores previos al 8086, estaban limitados en su desempeño por la necesidad de realizar los dos pasos principales de ejecución del procesador: Fetch/Execute, en forma secuencial. Es decir, no se puede ejecutar una instrucción hasta que se traiga de memoria (Fetch); y no podían traerse instrucciones de memoria mientras ejecutaba una instrucción, pues el procesador estaba ocupado.
• Resumiendo, un alto porcentaje del tiempo, el procesador estaba ocupado haciendo Fetch, cuando su función debiera ser ejecutar las instrucciones. La capacidad de ejecutar instrucciones sólo se ocupaba en un bajo porcentaje.
Arquitectura en pipeline • Para solucionar ésto, Intel desarrolló la arquitectura en pipeline del Fetch/Execute, en la cual simplemente se divide la tarea en dos secciones: una encargada del Fetch (BIU) y otra del Execute (EU).
– De esta manera, existen circuitos separados para cada función, los cuales trabajan en paralelo. – Si bien el proceso aún es secuencial, solamente al principio se requiere desperdiciar tiempo en el Fetch. – A partir de ahí, Fetch va adelante del Execute, y trae instrucciones al procesador mientras este ejecuta las anteriores.
Arquitectura del 8086/8088
Estos microprocesadores tiene 2 procesadores conectados internamente, estos procesadores son: EU Unidad de ejecución (Execution Unit). BIU Unidad de interfaz con el Bus (Bus Interface Unit).
La unidad de ejecución (EU) • La unidad de ejecución (EU) se encarga de realizar las operaciones aritméticas y lógicas, además de proporcionar las direcciones lógicas al BIU --una dirección lógica está formada de dos direcciones, la primera indica el segmento en el cual se está trabajando y la otra indica el offset, o desplazamiento, de este segmento; esto es segment:offset --. • La EU tiene una unidad aritmética lógica (ALU) de 16 bits, un registro de banderas y un conjunto de registros de propósito general. El registro de banderas contiene 6 banderas de estado (que la EU manipula para indicar el estado del resultado de una operación lógica o aritmética) y 3 banderas de control que se pueden manipular por los programas para alterar las operaciones del procesador .
La Unidad de Interfaz con el Bus (BIU) • Es la responsable de la comunicación externa del procesador. Esta unidad de proceso se encarga de traducir las direcciones lógicas a direcciones físicas de la memoria con ayuda de los registros de segmento DS, SS, ES, CS e IP. • Para convertir una dirección lógica en una dirección física el BIU corre el valor del registro de segmento 4 posiciones a la izquierda (que es equivalente a multiplicar por 16h) y suma el valor del offset para obtener un valor de 20 bits.
MODELO DE PROGRAMACIÓN DEL 8086.
El modelo de programación del 8086
Registros de datos o de propósito general AX, BX, CX, DX: pueden utilizarse bien como registros de 16 bits o como dos registros separados de 8 bits (byte superior e inferior) cambiando la X por H o L según queramos referirnos a la parte alta o baja respectivamente. Por ejemplo, AX se descompone en AH (parte alta) y AL (parte baja). Evidentemente, ¡cualquier cambio sobre AH o AL altera AX
AX = Acumulador. Es el registro principal, es utilizado en las instrucciones de multiplicación y división y en algunas instrucciones aritméticas especializadas, así como en ciertas operaciones de carácter específico como entrada, salida y traducción. Obsérvese que el 8086 es suficientemente potente para realizar las operaciones lógicas, la suma y la resta sobre cualquier registro de datos, no necesariamente el acumulador.
Registros de propósito general BX = Base. Se usa como registro base para referenciar direcciones de memoria con direccionamiento indirecto, manteniendo la dirección de la base o comienzo de tablas o matrices. De esta manera, no es preciso indicar una posición de memoria fija, sino la número BX (así, haciendo avanzar de unidad en unidad a BX, por ejemplo, se puede ir accediendo a un gran bloque de memoria en un bucle). CX = Contador. Se utiliza comúnmente como contador en bucles y operaciones repetitivas de manejo de cadenas. En las instrucciones de desplazamiento y rotación se utiliza como contador de 8 bits. DX = Datos. Usado en conjunción con AX en las operaciones de multiplicación y división que involucran o generan datos de 32 bits. En las de entrada y salida se emplea para especificar la dirección del puerto E/S.
Registros de segmento: Definen áreas de 64 KB dentro del espacio de direcciones de 1 MB del 8086. Estas áreas pueden traslaparse total o parcialmente. No es posible acceder a una posición de memoria no definida por algún segmento: si es preciso, habrá de moverse alguno. CS = Registro de segmento de código (code segment). Contiene la dirección del segmento con las instrucciones del programa. Los programas de más de 64 Kb requieren cambiar CS periódicamente. DS = Registro de segmento de datos (data segment). Segmento del área de datos del programa. SS = Registro de segmento de pila (stack segment). Segmento de pila. ES = Registro de segmento extra (extra segment). Segmento de ampliación para zona de datos. Es extraordinariamente útil actuando en conjunción con DS: con ambos se puede definir dos zonas de 64 Kb, tan alejadas como se desee en el espacio de direcciones, entre las que se pueden intercambiar datos
Registros punteros de pila
SP = Puntero de pila (stack pointer). Apunta al inicio de la pila. Utilizado en las instrucciones de manejo de la pila. BP = Puntero base (base pointer). Es un puntero de base, que apunta a una zona dentro de la pila dedicada al almacenamiento de datos (variables locales y parámetros de las funciones en los programas compilados).
Puntero de instrucciones o contador de programa IP = Puntero de instrucción (instruction pointer). Marca el desplazamiento de la instrucción en curso dentro del segmento de código. Es automáticamente modificado con la lectura de una instrucción.
Registros índices: SI = Índice fuente (source index). Utilizado como registro de índice en ciertos modos de direccionamiento indirecto, también se emplea para guardar un valor de desplazamiento en operaciones de cadenas. DI = Índice destino (destination index). Se usa en determinados modos de direccionamiento indirecto y para almacenar un desplazamiento en operaciones con cadenas.
Registro de estado o de indicadores (flags) • Es un registro de 16 bits de los cuales 9 son utilizados para indicar diversas situaciones durante la ejecución de un programa. • Los bits 0, 2, 4, 6, 7 y 11 son indicadores de condición, que reflejan los resultados de operaciones del programa • los bits del 8 al 10 son indicadores de control y el resto no se utilizan. • Estos indicadores pueden ser comprobados por las instrucciones de salto condicional, lo que permite variar el flujo secuencial del programa según el resultado de las operaciones.
Banderas del 8086 Bit CF
Indicador de: Acarreo ("Carry Flag")
Uso Indicador de arrastre del bit de mayor orden, que puede ocurrir en las operaciones aritméticas suma y resta. Si está activo Indica un número par de bits activos (bits cuyo contenido es 1). Esta información es útil cuando el procesador controla transmisiones de datos. Indicador de ajuste en operaciones aritméticas con cantidades BCD
PF
Paridad ("Parity Flag")
AF
Acarreo auxiliar
ZF
Cero ("Zero Flag")
Está activo si el resultado de operación es cero o resultado de comparación igual.
SF
Signo ("Sign Flag")
Si está activo indica que el resultado de operación o de comparación son negativos.
Detención ("Trap Flag")
Si está activo, el procesador genera automáticamente una interrupción después de la ejecución de cada instrucción, lo que permite controlar paso a paso la ejecución del programa. Este bit debe estar normalmente inactivo (a 0).
IF
Interrupción ("Interrupt Flag")
Este bit controla el estado del sistema de interrupciones enmascarables . Cuando está activo (1) permite las interrupciones; el estado inactivo (0) las deshabilita.
DF
Dirección ("Direction Flag")
Indica la dirección de las operaciones.
OF
Desbordamiento (Overflow Flag")
Señala desbordamiento aritmético
TF
Bit
Indicador de:
Indicativo si bit 1
Indicativo si bit 0
CF
Acarreo
CY ("Carry yes")
NC ("No Carry")
PF
Paridad
PE ("Parity Even") paridad par
PO ("Parity Odd") paridad impar
AF
Acarreo auxiliar
AC ("Auxiliar Carry")
NA ("No Auxiliar")
ZF
Cero
ZR ("Zero")
NZ ("No Zero")
SF
Signo
NG ("Negative") negativo
PL ("Plus") positivo
IF
Interrupción
EI ("Enabled Interrupt") activa
DI ("Disabled Interrupt") desactivada
D F
Dirección
DN ("Down") decremento
UP incremento
O F
Desbordamiento
OV ("Overflow")
NV ("No overflow")
Segmentación de la Memoria en el 8086
SEGMENTACIÓN FFFFF
Dirección lógica Dirección física SEGMENTO
Desplaza miento
Registro de segmento
Dirección de segmento
U 0
Memoria
Segmento de Memoria FFFFF
•
SEGMENTO
0
Memoria
Un segmento es un área continua de memoria que puede tener hasta 64K-bytes, que debe comenzar en una localidad de memoria cuya dirección sea límite de 16 bytes (cantidad denominada párrafo) y que puede traslaparse con otros segmentos.
Segmentos de Memoria El segmento de código (tiene como base el contenido del registro CS). En este segmento se encuentran las instrucciones que forman el programa. Para acceder a los datos contenidos en él, se usa el registro IP como desplazamiento. El segmento de datos (que tiene como base el registro DS). Contiene los datos que utiliza el programa (variables, etc.) Para acceder a los datos contenidos en él, se suele utilizar los registros SI y DI como desplazamiento.
Segmentos de Memoria - El segmento de pila (con SS como base). - En él se desarrolla la pila del programa, utilizada para almacén temporal de datos, llamadas a funciones, etc. Debe estar presente en todos los programas EXE de forma obligada. Se utiliza el registro SP para acceder a los datos de este segmento. - El segmento extra (con ES como base). - Su uso es opcional, y en él se encuentra un segmento definido por el y que, regularmente, contiene datos adicionales. Al igual que ocurre con el segmento de datos, para acceder a los datos contenidos en él, se suelen utilizar los registros SI y DI.
SEGMENTACIÓN TRASLAPE DE SEGMENTOS
CS
CS SEGMENTO DE CÓDIGO
PROGRAMA
SEGMENTO DE CÓDIGO
DS SEGMENTO DE DATOS
OTRO SEGMENTO
ES
SEGMENTO EXTRA DE DATOS SS STACK
MEMORIA
MEMORIA
SEGMENTACIÓN Relocalización de un programa usando el registro CS
02000 600 PROGRAMA
SEGMENTO DE CÓDIGO EN CURSO
nuevo (CS)=1A30
1A300 600 PROGRAMA
MEMORIA
SEGMENTO DE CÓDIGO RELOCALIZADO
Dirección Física y Dirección Lógica Cada localidad de memoria tiene dos tipos de direcciones : Dirección Física y Dirección Lógica o efectiva Una dirección Física es el valor único de 20 bits que identifica la localización de cada byte en el espacio de memoria de 1 Mbyte. Los programas tratan con dirección Lógicas mas que con la dirección Física.
Dirección Física y Dirección Lógica • Para cualquier localidad de memoria, el valor base del segmento ubica el primer byte del contenido del segmento y el valor del offset es la distancia, en bytes , de la localización destino del principio del segmento. • Los valores de la base del Segmento y del offset son cantidades no signadas de 16 bits; la dirección del byte más bajo del segmento tiene un offset 0.
Formación de una Dirección Física Siempre que una memoria es accesada , se genera una dirección física a partir de la dirección lógica. Dirección efectiva, lógica u offset
+
Dirección de segmento
Dirección física
20 BITS
4 bits 0000
EL REGISTRO DE SEGMENTO SE DESPLAZA 4 BITS HACIA LA IZQUIERDA (MULTIPLICACIÓN x16)
Formación de una Dirección Física
Formación de una Dirección Física Por Ejemplo: Si la dirección base del segmento es 2915h, entonces las direcciones en este segmento inician en 2915:0000 y van hasta 2915:FFFF