协处理器的结构
协处理器,顾名思 义,是为与CPU协同工作而设计的,其主要用来提高进行数学和超越函数计算的速度。在80486DX和Pentium处理器中都内置一个与80387完全 兼容的协处理器。CPU执行所有的常规指令,协处理器则执行协处理器指令,它们能同时并行地执行各自的指令。由于现在Pentium处理器内部结构的特 点,该处理器能同时执行一条协处理器指令和二条整数指令。
11.2.1 协处理器的内部结构
协处理器80x87的内部结构如图11.4所示。它可分为二个主要部分:控制部件(CU)和数值执行部件(NEU)。
| |
|
控制部件(CU)把协处理器接到CPU的系统总线上,协处理器和CPU都监视正在执行的指令流。如果当前将要执行的指令是协处理器指令(即:ESCape指令),那么,协处理器会自动执行它,否则,该指令将交给CPU来执行。
数值执行部件(NEU)复制执行所有的协处理器指令,它有一个用8个80位的寄存器组成的堆栈,该堆栈用于以扩展精度的浮点数据格式来存放数学指令的操作数和运算结果。在协处理器指令的执行过程中,要么指定该堆栈寄存器中的数据,要么使用压栈/出栈机制来从栈顶存放或读取数据。
在NEU部件中,还有一些记录协处理器工作状态的寄存器,如:状态寄存器、控制寄存器、标记寄存器和异常指针寄存器等。有关这些寄存器的作用将在后面给予分别介绍。
11.2.2 状态寄存器
状态寄存器是用来标识协处理器中指令执行情况的,它相当于CPU中的标志位寄存器。80x87协处理器的状态寄存器如图11.5所示。
| 15 |
|
13 |
12 |
11 |
|
|
8 |
7 |
|
|
|
|
|
|
0 |
| B |
C3 |
TOP |
C2 |
C1 |
C0 |
ES |
SF |
PE |
UE |
OE |
ZE |
DE |
IE |
||
图11.5 80x87协处理器的状态寄存器示意图
状态寄存器各标志位(或组合位)的含义如下:
◆ B(Busy,忙)
忙标志位用来表明协处理器是否正在执行协处理器指令,它可用FWAIT指令来测试。在80287及其以后的协处理器中,协处理器和CPU能自动实现同步,所以,现在在运行任务时,无须测试忙标志。
◆C3~C0(条件编码位)
四位条件编码位的组合含义如表11.2所列。
表11.2 状态寄存器中条件编码位的组合含义
| 指 令 |
C3 |
C2 |
C1 |
C0 |
功 能 |
| FTST、FCOM |
0 |
0 |
X |
0 |
ST>操作数或(0 FTST) |
| 0 |
0 |
X |
1 |
ST<操作数或(0 FTST) |
|
| 1 |
0 |
X |
0 |
ST=操作数或(0 FTST) |
|
| 1 |
1 |
X |
1 |
ST不可比较 |
|
| FPREM |
Q1 |
0 |
Q0 |
Q2 |
Q2Q1Q0是商的右边3位 |
| ? |
1 |
? |
? |
未完成 |
|
| FXAM |
0 |
0 |
0 |
0 |
unnormal |
| 0 |
0 |
0 |
1 |
NAN |
|
| 0 |
0 |
1 |
0 |
-unnormal |
|
| 0 |
0 |
1 |
1 |
-NAN |
|
| 0 |
1 |
0 |
0 |
normal |
|
| 0 |
1 |
0 |
1 |
∞ |
|
| 0 |
1 |
1 |
0 |
-unnormal |
|
| 0 |
1 |
1 |
1 |
-∞ |
|
| 1 |
0 |
0 |
0 |
0 |
|
| 1 |
0 |
0 |
1 |
空 |
|
| 1 |
0 |
1 |
0 |
-0 |
|
| 1 |
0 |
1 |
1 |
空 |
|
| 1 |
1 |
0 |
0 |
denormal |
|
| 1 |
1 |
0 |
1 |
空 |
|
| 1 |
1 |
1 |
0 |
-denormal |
|
| 1 |
1 |
1 |
1 |
空 |
其中,normal—标准的浮点数,unnormal—有效数字前面是0,如:0.XXXX,denormal—阶码是最大的负值,NAN—见11.1.3节中几个特殊数据的说明。
◆ TOP(栈顶)
该三位二进制000~111用来表明当前作为栈顶的寄存器,通常其值为000。
◆ ES(错误汇总)
ES=PE UE OE ZE DE IE(逻辑或运算),在8087协处理器中,当ES为1时,将发出一个协处理器中断请求,但在其后的协处理器中,不再产生这样的协处理器中断申请。
◆ SF(堆栈溢出错误)
该状态位用来表明协处理器内部的堆栈是否有上溢或下溢错误。
◆ PE(精度错误)
该状态位用来表明运算结果或操作数是否超过先前设定的精度。
◆UE(下溢错误)
该状态位用来表明一个非0的结果太小,不能用控制字节所选定的当前精度来表示。
◆OE(上溢错误)
该状态位用来表明一个非0的结果太大,不能用控制字节所选定的当前精度来表示,即超过了当前精度所能表示的数据范围。
如果在控制寄存器中屏蔽该错误标志,即设控制寄存器中的OM为1,那么,协处理器把上溢结果定义为无穷大。
◆ZE(除法错误)
该状态位用来表明当前执行了“0作除数”的除法运算。
◆DE(非规格化错误)
该状态位用来表明当前参与运算的操作数中至少有一个操作数是没有规格化的。
◆ IE(非法错误)
该状态位用来表明执行了一个错误的操作,如:求负数的平方根,也可用来表明堆栈的溢出错误、不确定的格式(0/0,∞,-∞等)错误,或用NAN作为操作数。
对于协处理器中状 态寄存器的内容,程序员可用指令FSTSW把其值送到内存单元中。如果当前使用的是80287及其以后的协处理器,那么,可用指令“FSTSW AX”把该状态寄存器的值传送给通用寄存器AX。一旦状态寄存器的值复制到内存或AX中,那么,就可对其各位进行分析,并可检测出当前协处理器的工作状 态。
对于80287协处理器,它还可通过I/O地址00FAH~00FFH来实现其与CPU之间的数据交换,而80387~Pentium系列芯片,则是通过I/O地址800000FAH~800000FFH来实现这两者之间的数据交换。
当状态寄存器的内容传给AX之后,一般可用下面二种方法来检测协处理器的状态。
方法1:用TEST指令来检测其相应的状态位。
例11.3 检测是否有“0作除数”的错误。
| |
FDIV |
DATA1 |
;用协处理器中堆顶数据去除DATA1 |
| FSTSW |
AX |
;把状态寄存器的值传送给AX |
|
| TEST |
AX, 4 |
;测试第2位,即:检测ZE是否为1 |
|
| JNZ |
DIV_ERR |
||
例11.4 检测是否有“非法操作数”的错误。
| |
FSQRT |
;求协处理器中堆顶数据的平方根 |
|
| FSTSW |
AX |
||
| TEST |
AX, 1 |
;测试第0位,即:检测IE是否为1 |
|
| JNZ |
SQRT_ERR |
||
方法2:用SAHF指令把AX的低字节传送给CPU的标志位寄存器,然后再用条件转移指令来完成相应的检测。
例11.5 检测内存单元的数据与协处理器堆顶数据之间的大小关系。
| |
FCOM |
DATA1 |
;内存单元DATA1的值与协处理器堆顶数据进行比较 |
| FSTSW |
AX |
||
| SAHF |
;把AX的低字节存入CPU的状态寄存器 |
||
| JE |
ST_EQUAL |
;具体大小关系的决定可见表11.2中的“FCOM” |
|
| JB |
ST_BELOW |
||
| JA |
ST_ABOVE |
||


