Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Introducción
El coprocesador matemático, 8087 tiene 8 registros de coma flotante de 80 bits, maneja enteros con signo,
BCD y punto flotante. El 8086/8088 deberá funcionar en modo máximo para trabajar con el 8087. Las
instrucciones del 8087 incluyen un juego completo de funciones: aritméticas, exponenciales, logarítmicas y
trigonométricas. Utiliza un formato interno de números en coma flotante de 80 bits con el cual gestiona siete
formatos exteriores. El 8087 posee 45.000 transistores y consume 3 watt.
Hay dos tipos de números que aparecen normalmente durante el cálculo: los números enteros y los números
reales. Aunque los enteros son un subconjunto de los reales, la computadora trabaja de formas distintas con
ambos. El microprocesador trabaja con números enteros utilizando la aritmética de precisión múltiple.
El coprocesador trabaja con números reales, que casi nunca pueden representarse exactamente; sin
embargo, en la práctica la representación en coma flotante permite una muy buena aproximación. Con este
sistema, la representación de un número consta de tres partes: el signo, el exponente y la mantisa.
Los enteros con signo pueden ser de 16 bits, que se definen con DW; de 32 bits, que se definen con DD y de
64 bits, que se definen con DQ. En los tres casos los números positivos se almacenan en formato verdadero
con un bit de signo igual a “0” en el extremo izquierdo. Los números negativos se almacenan en complemento
a dos, con el bit de signo igual a “1” en el extremo izquierdo.
Los números BCD requieren 80 bits. Se almacenan como enteros empaquetados de 18 dígitos en nueve
bytes con dos dígitos por byte. El décimo byte contiene el bit de signo. Los números positivos y negativos son
almacenados en formato real utilizando la directiva DT.
Los números en punto flotante o números reales, constan de tres partes: un bit de signo, un exponente
descentrado (bias) y una mantisa. Se pueden manejar tres tipos de números de punto flotante con el estándar
IEEE-754: real corto de 32 bits que se define con DD, real largo de 64 bits que se define con DQ y real
temporal de 80 bits que se define con DT.
Formato Rango Precisión Byte 9 Byte 8 Byte 7 Byte 6 Byte 5 Byte 4 Byte 3 Byte 2 Byte 1 Byte 0
Word 104 16 bits I15 I0
Integer Short 109 32 bits I31 I0
Long 1018 64 bits I63 I0
Packed BCD 1018 18 Digits S D17 D0
Short 10±38 24 bits S E1 E0 F8 F23
Real Long 10±308 53 bits S E10 E0 F4 F12 F20 F28 F36 F44 F52
Temporary 10±4932 64 bits S E8 E0 F0 F7 F15 F23 F31 F39 F47 F55 F63
Ii: Integer
Packed BCD: (-1)S(D17 … D0)
Real: (-1)S(2E-Bias) (F0•F1 … )
Bias = 7F for short real
3FF for long real
3FFF for temporary real
Tipos de datos del 8087
En los números reales Short y Long el bit F0 es implícito (F0•), esto se aclarará con un ejemplo. En los
números reales Temporary el bit F0 es explícito. Por precisión se entiende la exactitud de un número, en la
representación de coma flotante, la mantisa es la encargada de la precisión. El rango está relacionado con el
tamaño de los números que se pueden representar, en la notación de coma flotante, es el exponente el que
fija el rango
El número 0 se almacena como solo ceros, exceptuando el bit de signo, que puede ser “1” para representar
un cero negativo. El ±∞ se almacena con todos los bits del exponente en “1” y todos los bits de la mantisa en
“0” y el bit de signo en “1” negativo o “0” positivo. Finalmente un NAN (no es un número) es un resultado no
válido en punto flotante que tiene todos los bits del exponente en “1” y todos los bits de la mantisa en “0”.
Para ver esto en nuestro programa, simplemente definimos un número en el segmento de datos y escribimos
el encabezamiento de un programa que termina como .exe.
push ds
sub ax,ax
pùsh ax
mov ax,datos
mov ds,ax
Después de hacer correr, paso a paso el encabezamiento, podemos ver que en el segmento de datos se ve el
número en formato hexadecimal e invertido.
137 = 10001001
.25 x 2 = 0.5
.5 x 2 = 1
AD0 – AD15 S2
Registro de control
Registro de estado S1
A16/S3
Registro de marcas
S0
A17/S4
QS0
A18/S5
A19/S6
8087 QS1
BUSY
BHE/S7
READY
ST(0)
RQ/GT1
ST(1)
RESET
ST(2)
RQ/GT0
ST(3)
Vcc
ST(4)
INT
ST(5)
GND
ST(6)
CLK
ST(0)
Registro de estado
B Ocupado Indica que el 8087 está ocupado. Se evalúa mediante analizando el registro de estado o el uso de la instrucción
WAIT.
C0–C3 Código condición Indican condiciones relacionadas con el 8087. Estos bits tienen significados diferentes para distintas
instrucciones
TOP Apunta a la parte Indica el registro ST direccionado como parte superior de la pila, generalmente ST(0)
superior de la pila ST
ES Resumen de errores Se activa si los bits: PE, UE, OE, ZE, DE o IE
PE Precisión Indica que el resultado o los operandos se excedieron de la precisión seleccionada
UE Sub-desbordamiento Indica que el resultado es demasiado pequeño para representarlo con la precisión seleccionada
OE Sobre-desbordamiento Indica que el resultado es demasiado grande para representarlo con la precisión seleccionada
ZE División por cero Indica que el divisor es cero, el dividendo no es ni infinito ni cero
DE Operando no Indica que al menos uno de los operandos no está normalizado
normalizado
IE Operación no válida Indica error debido a operaciones del tipo 0/0, +∞, -∞, raíz de un número negativo, etc
Instrucción C3 C2 C1 C0 Indicación
0 0 X 0 ST > Operando, salto con la instrucción JA
0 0 X 1 ST < Operando, salto con la instrucción JB
FTST,FCOM
1 0 X 1 ST = Operando, salto con la instrucción JE
1 1 X 1 ST no puede compararse
Q1 0 Q0 Q2 Los 3 bits de más a la derecha del cociente
FPREM
? 1 ? ? Incompleto
FXAM 0 0 0 0 + anormal
0 0 0 1 + NAM
0 0 1 0 - anormal
0 0 1 1 - NAM
0 1 0 0 + normal
0 1 1 0 +∞
0 1 1 1 - normal
1 0 0 0 -∞
1 0 0 1 +0
1 0 1 0 Vacío
1 0 1 1 -0
1 1 0 0 Vacío
1 1 0 1 + no normal
1 1 1 0 - no normal
1 1 1 1 Vacío
Anormal = Los bits de la izquierda de la mantisa son cero
No normal = el exponente está en su valor más negativo
Normal = Formato de punto flotante estándar
NAN = Un exponente de solo unos y una mansita distinta de cero, el operando para TST es cero.
Ejemplo. Verificar si la división ST(0)/num es correcta. La variable num es el resultado de un proceso anterior
a la división
Ejemplo. Comparar ST(0) con num. La variable num es el resultado de un proceso anterior a la comparación
fcom num ; Compara ST(0) con num
fstsw ax ; Copia el registro de estado en AX
sahl ; Copia banderas del 8087 al flag register del 8086
je ST.igual ; Salta si es igual
jb ST.menor ; Salta si es menor
ja ST.mayor ; Salta si es mayor
Registro de control
El registro de etiquetas marca el contenido de cada registro ST. La función principal de las etiquetas es
optimizar el rendimiento del 8087. Sin embargo, las etiquetas pueden utilizarse para interpretar el contenido
de los registros del 8087.
FLD mem: Introduce una copia de mem en ST. La fuente debe ser un número real en
punto flotante de 4, 8 ó 10 bytes. Este operando se transforma automáticamente al
formato real temporal.
FLD ST(num): Introduce una copia de ST(num) en ST.
FILD mem: Introduce una copia de mem en ST. La fuente debe ser un operando de
memoria de 2, 4 u 8 bytes, que se interpreta como un número entero y se convierte
al formato real temporal.
FBLD mem: Introduce una copia de mem en ST. La fuente debe ser un operando de 10
bytes, que se interpreta como un valor BCD empaquetado y se convierte al formato
real temporal.
FST mem: Copia ST a mem sin afectar el puntero de pila. El destino puede ser un
operando real de 4 u 8 bytes (no el de 10 bytes).
FST ST(num): Copia ST al registro especificado.
FIST mem: Copia ST a mem. El destino debe ser un operando de 2 ó 4 bytes (no de 8
bytes) y se convierte automáticamente el número en formato temporal real a
entero.
FSTP mem: Extrae una copia de ST en mem. El destino puede ser un operando de
memoria de 4, 8 ó 10 bytes, donde se carga el número en punto flotante.
FSTP ST(num): Extrae ST hacia el registro especificado.
FISTP mem: Extrae una copia de ST en mem. El destino debe ser un operando de
memoria de 2, 4 u 8 bytes y se convierte automáticamente el número en formato
temporal real a entero.
FBSTP mem: Extrae una copia de ST en mem. El destino debe ser un operando de
memoria de 10 bytes. El valor se redondea a un valor entero, si es necesario, y
se convierte a BCD empaquetado.
FXCH: Intercambia ST(1) y ST.
FXCH ST(num): Intercambia ST(num) y ST.
Las constantes no se pueden ser operandos y ser cargados directamente en los registros del 8087. las
constantes debe estar ubicadas en memoria. Sin embargo, hay algunas instrucciones para cargar ciertas
constantes (0, 1, pi y algunas constantes logarítmicas).
El área de datos del 8087, o parte de él, puede ser guardado en memoria y luego se puede volver a cargar.
Una razón para hace esto es guardar una imagen del estado del coprocesador antes de llamar una subrutina
parea luego restaurar. Otra razón es para modificar el comportamiento del 8087, almacenando ciertos datos
en memoria, operar con los mismos utilizando instrucciones del 8086 y finalmente cargarlo de nuevo en el
coprocesador.
Se puede transferir el área de datos del coprocesador, los registros de control, o simplemente la palabra de
estado o de control.
Cada instrucción de carga tiene dos formas: La forma con espera verifica excepciones de errores numéricos
no enmascarados y espera a que sean atendidos. La forma sin espera (cuyo mnemotécnico comienza con
"FN") ignora excepciones sin enmascarar. Aquí [N] significa opcional.
Instrucciones aritméticas
Cuando se usan operandos de memoria con una instrucción aritmética, el mnemotécnico de la instrucción
distingue entre número real y número entero. No se pueden realizar operaciones aritméticas con números
BCD empaquetados en la memoria, Para esto se usa FBLD que carga números BCD desde la memoria.
FADD: Hace ST(1) más ST, ajusta el puntero de pila y pone el resultado en ST, por
lo que ambos operandos se destruyen.
FADD mem: Hace ST <- ST + [mem]. En mem deberá haber un número real en punto
flotante.
FIADD mem: Hace ST <- ST + [mem]. En mem deberá haber un número entero en
complemento a dos.
FADD ST(num), ST: Realiza ST(num) <- ST(num) + ST.
FADD ST, ST(num): Realiza ST <- ST + ST(num).
FADDP ST(num), ST: Realiza ST(num) <- ST(num) + ST y retira el valor de ST de la
pila, con lo que ambos operandos se destruyen.
FSUB: Hace ST(1) menos ST, ajusta el puntero de pila y pone el resultado en ST,
por lo que ambos operandos se destruyen.
FSUB mem: Hace ST <- ST - [mem]. En mem deberá haber un número real en punto
flotante.
FISUB mem: Hace ST <- ST - [mem]. En mem deberá haber un número entero en
complemento a dos.
FSUB ST(num), ST: Realiza ST(num) <- ST(num) - ST.
FSUB ST, ST(num): Realiza ST <- ST - ST(num).
FSUBP ST(num), ST: Realiza ST(num) <- ST(num) - ST y retira el valor de ST de la
pila, con lo que ambos operandos se destruyen.
FSUBR: Hace ST menos ST(1), ajusta el puntero de pila y pone el resultado en ST,
por lo que ambos operandos se destruyen.
FSUBR mem: Hace ST <- [mem] - ST. En mem deberá haber un número real en punto
flotante.
FISUBR mem: Hace ST <- [mem] - ST. En mem deberá haber un número entero en
complemento a dos.
FSUBR ST(num), ST: Realiza ST(num) <- ST - ST(num).
FSUBR ST, ST(num): Realiza ST <- ST(num) - ST.
FSUBRP ST(num), ST: Realiza ST(num) <- ST - ST(num) y retira el valor de ST de la
pila, con lo que ambos operandos se destruyen.
FMUL: Multiplicar el valor de ST(1) por ST, ajusta el puntero de pila y pone el
resultado en ST, por lo que ambos operandos se destruyen.
FMUL mem: Hace ST <- ST * [mem]. En mem deberá haber un número real en punto
flotante.
FIMUL mem: Hace ST <- ST * [mem]. En mem deberá haber un número entero en
complemento a dos.
FMUL ST(num), ST: Realiza ST(num) <- ST(num) * ST.
FMUL ST, ST(num): Realiza ST <- ST * ST(num).
FMULP ST(num), ST: Realiza ST(num) <- ST(num) * ST y retira el valor de ST de la
pila, con lo que ambos operandos se destruyen.
FDIV: Dividir el valor de ST(1) por ST, ajusta el puntero de pila y pone el
resultado en ST, por lo que ambos operandos se destruyen.
FDIV mem: Hace ST <- ST / [mem]. En mem deberá haber un número real en punto
flotante.
FIDIV mem: Hace ST <- ST / [mem]. En mem deberá haber un número entero en
complemento a dos.
FDIV ST(num), ST: Realiza ST(num) <- ST(num) / ST.
FDIV ST, ST(num): Realiza ST <- ST / ST(num).
FDIVP ST(num), ST: Realiza ST(num) <- ST(num) / ST y retira el valor de ST de la
pila, con lo que ambos operandos se destruyen.
FDIVR: Hace ST dividido ST(1), ajusta el puntero de pila y pone el resultado en
ST, por lo que ambos operandos se destruyen.
FDIVR mem: Hace ST <- [mem] / ST. En mem deberá haber un número real en punto
flotante.
FIDIVR mem: Hace ST <- [mem] / ST. En mem deberá haber un número entero en
complemento a dos.
FDIVR ST(num), ST: Realiza ST(num) <- ST / ST(num).
FDIVR ST, ST(num): Realiza ST <- ST(num) / ST.
FDIVRP ST(num), ST: Realiza ST(num) <- ST / ST(num) y retira el valor de ST de la
pila, con lo que ambos operandos se destruyen.
FABS: Pone el signo de ST a positivo (valor absoluto).
FCHS: Cambia el signo de ST.
FRNDINT: Redondea ST a un entero.
FSQRT: Reemplaza ST con su raíz cuadrada.
FSCALE: Suma el valor de ST(1) al exponente del valor en ST. Esto efectivamente
multiplica ST por dos a la potencia contenida en ST(1). ST(1) debe ser un número
entero.
FPREM: Calcula el resto parcial hallando el módulo de la división de los dos
registros de la pila que están el tope. El valor de ST se divide por el de ST(1).
El resto reemplaza el valor de ST. El valor de ST(1) no cambia. Como esta
instrucción realiza sustracciones repetidas, puede tomar mucho tiempo si los
operandos son muy diferentes en magnitud. Esta instrucción se utiliza a veces en
funciones trigonométricas.
FXTRACT: Luego de esta operación, ST contiene el valor de la mantisa original y
ST(1) el del exponente.
Instrucciones trascendentales
Ejecutando el programa copro1.exe con el turbo debuger tenemos y copro2.exe con el turbo debuger tenemos
Se ve la diferencia con recuadro rojo en ambas figuras.
copro1.asm copro2.asm
.386 .386
.387 .387
;------------------------------------------------------------------------- ;-------------------------------------------------------------------------
datos segment para 'data' datos segment para 'data'
dato1 dd -3.1415 ;precision sencilla angulo dw 45
dato3 dd 15 ;numeros enteros seno dw 0 ;seno(angulo)
datos ends datos ends
;------------------------------------------------------------------------- ;-------------------------------------------------------------------------
codigo segment para 'code' codigo segment use16
Esto se debe a que en el programa copro1.asm el segmento de código no permite utilizar registros de 16 bits.
Para utilizar registros de 16 bits acudimos a la directiva use16. Esto se ve en el programa copro2.asm.
Entonces para examinar el programa copro1.asm, primero debe cambiar el segmento de código como se ve
en la figura.
En el programa copro1.asm verá la diferencia de manejar números enteros y números reales. Para esto
primero se muestra como ver los registros del coprocesador numerico 8087.
Una vez que este viendo los registros de 8087 haga correr el programa paso a paso. Verá como se cargan los
números -3,1415 y 3.0 con fld y se suman con fadd para luego depositar el resultado en la variable suma,
con fstp.
Luego vera como se carga el número 15, con fild y se suma directamente con el número 30, con fiadd, que
esta en la memoria administrada por el microprocesador, luego la suma la depositamos en la variable suma1,
utilizando fst. El estudiante esta en la obligación de ver la diferencia entre las instrucciones fstp y fst.
Con la ayuda del programa copro1.asm el estudiante deberá verificar la representación de números reales
utilizando el estandar IEEE-754.
El programa copro2.asm calcula el seno de angulo = 45o. Primera observación. Haga correr el programa paso
a paso. Cuando llegue a la instrucción fsin, verá que en realidad se ejecuta la instrucción fcos, por esta razón
utilizamos sin(x) = cos(x-90). Segunda observación. El coprocesador matemático trabaja con radianes, por
tanto hay que convertir los grados a radianes. Finalmente multiplicamos por cien y redondeamos. Esto para
dibujar en una pantalla gráfica.
El programa copro3.asm y el programa copro4.asm dibujan la función y(t) = Asin(t). Para terminar el programa
copro5.asm despliega el número -1964.9898, que está definido en el segmento de datos, en una pantalla
80x25 modo texto. Vea que en realidad se despliega -1964.98828125 ¿Cuan cree que es la razón? Justifique
su respuesta.
Tarea
Utilizando el coprocesador matemático, en una pantalla con una resolución 1024x768x256 dibuje la respuesta
temporal de un circuito RLC, es decir la respuesta a la señal paso.
La interfaz de usuario permite determinar los valores numéricos de los parámetros de la respuesta temporal,
es decir ¿cuanto vale td, tr, tp, ts y Mp?
Fecha de entrega