协处理器指令系统
协处理器共有68条不同的指令,汇编程序在遇到协处理器指令助记符时,都会将其转换成机器语言的ESC指令,ESC指令代表了协处理器的操作码。
协处理器指令在执行过程中,需要访问内存单元时,CPU会为其形成内存地址。协处理器在指令执行期间内利用数据总线来传递数据。80287协处理器利用I/O地址00FAH~00FFH来实现其与CPU之间的数据交换,而80387~Pentium系列芯片,则是利用I/O地址800000FAH~800000FFH来实现这两者之间的数据交换。
协处理器指令的操作符(或助忆符)在命名设计时,遵循了下列规则:
1、在操作符后面加上字母P:表示该指令执行完后,还进行一次堆栈弹出操作,弹出栈顶数据以后要对其它的寄存器进行相应的调整。如:FADDP/FSUBP/FSUBRP /FMULP/FDIVP /FDIVRP等;
2、在操作符后面加上字母R:表示将两个操作数的源/目的位置交换再进行运算,它仅限于减法、除法指令,因为加法和乘法不受源/目的操作数的位置影响结果。如:FSUBR和FDIVR等;
不加R时 —— 目的操作数=目的操作数 op 源操作数
加R模式 —— 目的操作数=源操作数 op 目的操作数
假设:栈顶数据st(0)为10,内存变量data的值为1,分别执行下列指令将有不同的结果。
FSUB data ; ST(0)=ST(0)-data
FSUBR data ;ST(0)=data-ST(0)
FSUB ST(3), ST(0) ;指令执行后,ST(3)=ST(3)-ST(0)
FSUBR ST(3), ST(0) ;指令执行后,ST(3)=ST(0)-ST(3)
3、操作符的第2个字母是I:表示内存操作数是整数(注意:不能是BYTE类型)。它对加、减、乘、除指令以及堆栈操作指令都有效。
FIADD data —— 整数加法,它表示内存单元data是一个整数,把该整数加到栈顶的浮点数上(ST(0)=ST(0)+data)。
4、操作符的第二个字母是B:表示用于操作压缩的BCD码格式的内存操作数(用TWORD声明,10个字节),如FBLD和FBSTP等。
5、操作符的第2个字母是N:表示在指令执行之前检查非屏蔽数值性错误。如:FSAVE和FNSAVE等,前者称为等待形式(wait version),后者称为非等待形式(no-wait version)。
在使用.8087伪指令情况下,汇编程序会在等待形式的指令前面加上指令WAIT,而在非等待形式的指令前面加上空操作指令NOP。
理解了上述操作符命名规则,就能很容易地区分同类指令之间的差异。
二.数据传送指令
为了满足协处理器和CPU之间进行数据交流的需求,就需要实现内存单元和协处理器之间进行数据传送的指令。协处理器的指令系统中有三大类数据传送指令:BCD传送指令、数传送指令和浮点数传送指令。
(一)、BCD传送指令
1、FBLD
指令格式:FBLD MemBCD
指令功能:将操作数中的BCD数据压入协处理器的堆栈中(ST(0)=MemBCD);MemBCD是TWORD类型的内存变量。
2、FBSTP
指令格式:FBSTP MemBCD
指令功能:将协处理器中的BCD数据存入内存(MemBCD=ST(0)),并进行堆栈的弹出操作。
例如:
.387 data1 DT 123, -543 data2 DT 2.5 …… FBLD data1 FBSTP data |
;把data1压进栈(ST(0)=data1) ;把当前堆顶数据弹出,并传送给data (data=ST(0)) |
(二)、整数传送指令
1、FILD
指令格式:FILD MemInt ;ST(0)=MemInt
其中:MemInt是定义为整型数据类型的内存单元,但不能是用BYTE定义的存储单元。下同,不再叙述。
2、FIST/FISTP
指令格式: 其中: 指令功能: |
FIST MemInt Mem是定义整型数据类型的内存单元,(用WORD,DWORD和QWORD定义)。 将协处理器堆栈栈顶的数据传送到目标存储单元中。在进行数据传送时,系统自动根据控制寄存器中舍入控制位的设置把栈顶浮点数舍入成整型数据。 |
而FIST与FISTP的区别在以前就讲过,在执令后加P的表示带有出栈操作。那么FIST的功能是MemInt=ST(0),但ST(0)不出栈,但FISTP则在进行传送之后再进行对栈顶进行出栈。
(三)、浮点数传送指令
1、FLD
指令格式:
FLD STReg/MemReal
指令功能:
将浮点数据压入协处理器的堆栈中。当进行内存单元内容压栈时,系统会自动决定传送数据的精度。比如:用DD或REAL4定义的内存单元数值是单精度数等。
STReg是处理器堆栈寄存器ST(0)~ST(7)。
例如:
.387 data1 DWORD 123, -543 data2 REAL8 -321.5 data3 REAL10 2.5 …… FLD data1 ;压一个单精度数据进栈 FLD data2 ;压一个双精度数据进栈 FLD ST(0) ;把堆栈寄存器ST(0)的值再压进栈 FLD data3 ;压一个扩展精度数据进栈 |
2、FST
指令格式: 指令功能: |
FST STReg/MemReal 将协处理器堆栈栈顶的数据传送到目标操作数中。在进行数据传送时,系统自动根据控制寄存器中舍入控制位的设置把栈顶浮点数舍入成相应精度的数据。 |
3、FSTP
指令格式: |
FSTP STReg/MemReal |
|
指令功能: |
与FST相类似,所不同的是:指令FST执行完后,不进行堆栈的弹出操作,即:堆栈不发生变化,而指令FSTP执行完后,则需要进行堆栈的弹出操作,堆栈将发生变化。 |
从上面的浮点传送指令中可以看出,不仅可以对内存变量进行传送,也可以进行寄存器之间的传送,这一点是整型数据以及BCD型数据传送指令所不具有的。
4、FXCH
指令格式: 指令功能: |
FXCH [STReg] 将指定的寄存器中的浮点数与堆顶浮点数进行交换。如果不指定操作数,那么,默认ST(0)和ST(1)二者之间交换数据。 |
例如:FXCH ST(2) —— ST(0)与堆栈寄存器ST(2)进行数据交换。
由于FXCH指令隐含ST(0)作为其中的一个操作数,所以其后只需指定一个操作数,但该操作数必须是寄存器,而且不能为ST(0),但是该指令后的寄存器是可选的,如果没有指定寄存器操作数,那么隐含是对ST(1)和ST(0)进行交换。
对数据传送指令的一点总结:它包括三种数据的传送指令,整型,压缩的BCD型以及实型,三种数据的传送有各自的指令集。
压缩的BCD传送指令仅有压栈以及弹栈两条:FBLD以及FBSTP,它们都仅有一个操作数,而且操作数必须是内存操作数的TWORD类型。
整型数据传送指令有三条:FILD、FIST和FISTP,其中后两条是出栈,唯一的区别在于出栈后是否改变(弹出)栈顶数据。它们都仅有一个操作数,而且操作数必须是内存操作数的WORD、DWORD以及QWORD类型,不能为BYTE类型。
相对来讲,实数传送指令比较多,它一共有四条:FLD、FST、FSTP和FXCH。前三条指令的用法与整型类似,只不过用于传送实型数据,而且三条指令不仅支持内存操作数(为REAL4、REAL8和REAL10类型),而且支持寄存器之间的传送。三条指令同样需要一个操作数。而对于FXCH指令,它可以有一个或者没有操作数,但如果有操作数,那么这个参数必须为寄存器。
三.算术运算指令
在协处理器的指令系统中,有关数学运算指令有:加法指令、减法指令、乘法指令、除法指令和求平方根指令等。涉及数学运算的指令有比例运算、舍入运算、求绝对值运算和改变数值符号运算等指令。
(一)、整型算术运算指令
指令格式:
FIADD MemInt ;加法指令
FISUB MemInt ;减法指令
FISUBR MemInt ;减法指令
FIMUL MemInt ;乘法指令
FIDIV MemInt ;除法指令
FIDIVR MemInt ;除法指令
指令说明:
由于整型算术运算指令都仅有一个操作数,那么另一个操作数就被隐含成ST(0),而运算结果也被保存在ST(0)中。
加和乘都仅有一条指令,它们的运算规则为:
ST(0)=ST(0)+MemInt
ST(0)=ST(0)*MemInt
但减法和除法都分别有两条指令,后面带R的指令是在运算之前先交换源/目的操作数的位置再进行运算。由于在加法和乘法运算中交换两个操作数的位置的运算结果是一样的,所以不存在加R的情况。
减法和除法的运算规则为:
ST(0)=ST(0)-MemInt ;相对于FISUB指令。
ST(0)=MemInt-ST(0) ;相对于FISUBR指令。
ST(0)=ST(0)/MemInt ;相对于FIDIV指令。
ST(0)=MemInt/ST(0) ;相对于FIDIVR指令。
综上所述,在进行整型算术运算中,仅须指定一个内存操作数就可以了,另一个操作数则默认为是ST(0),并且结果也存放在ST(0)中。
(二)、实型算术运算指令
1.不带弹出操作的算术运算指令。
指令格式:
FADD [STReg1, STReg2] ;加法指令。
FADD MemReal ;加法指令。
FSUB [STReg1, STReg2] ;减法指令
FSUB MemReal ;减法指令
FSUBR [STReg1, STReg2] ;减法指令
FSUBR MemReal ;减法指令
FMUL [STReg1, STReg2] ;乘法指令
FMUL MemReal ;乘法指令
FDIV [STReg1, STReg2] ;除法指令
FDIV MemReal ;除法指令
FDIVR [STReg1, STReg2] ;除法指令
FDIVR MemReal ;除法指令
上面的指令可以分为带R和不带R,区别在以前就讲过。从上面的格式可以看出,它们都有三种使用格式:
(1) 不带任何操作数。
如果不带操作数,那么FPU就默认为ST(1)作为目的操作数,而ST(0)作为源操作数。但这种情况下有一个弹出的动作,如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FLD Val2 ;ST(0)=4.13 ST(1)=3.14
FSUB ;ST(1)=ST(1)-ST(0)=3.14-4.13=-0.99,再弹出ST(0)
也就是说执行过程是ST(1)=ST(1) op ST(0),再将ST(0)弹出,那么ST(1)就变成ST(0),而原来的ST(0)就被弹出了。这一点是初学者最容易忘记的地方,在不带有P的算术运算指令进行实数运算,并且不指定任何操作数的时候,指令默认有一个弹出操作。但这个规则仅用于实型算术运算,因为整型算术运算有一个操作数。
(2) 带有一个操作数。
从上面的指令格式可以看出,如果带有一个操作数,那么这个操作数必须是内存操作数,在这种情况下,将ST(0)与该操作数进行运算,不管源/目的操作数位置如何,结果都存入ST(0)中(注意:这种情况没有弹出动作)。例如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FSUB Val2 ;ST(0)=ST(0)-Val2=3.14-4.13=-0.99
而在上面的FSUB带一个R的话,即
FSUBR Val2
那么就进行ST(0)=Val2-ST(0)的运算。
(3) 带两个操作数。
如果带有两个操作数,那么两个操作数必须都为寄存器,而且其中一个寄存器必须为ST(0)。结果存入目的寄存器中,同样这种情况不带弹出动作。例如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FLD Val2 ;ST(0)=4.13 ,ST(1)=3.14
FSUB ST(0),ST(1)
那么,ST(0)=ST(0)-ST(1)=4.13-3.14=0.99,但ST(1)的值不变,还是为3.14。如果写成:
FSUB ST(1),ST(0)
那么,ST(1)=ST(1)-ST(0)=3.14-4.13=-0.99,而ST(0)值不变。
2.带弹出操作的算术运算指令
指令格式:
FADDP STReg, ST ;加法指令
FSUBP STReg, ST ;减法指令
FSUBRP STReg,ST ;减法指令
FMULP STReg, ST ;乘法指令
FDIVP STReg, ST ;除法指令
FDIVRP STReg, ST ;除法指令
由于所有的指令都带P,那么都有弹出动作,从指令格式中可以看出,它们都有两个操作数,而且俩操作数都是寄存器,源操作数都是ST(0)寄存器,而目的操作数是ST(1)~ST(7)中的任何一个,但不能是ST(0)。在进行运算时,运算结果存入目的寄存器中(ST(1)~ST(7)),然后对ST(0)进行弹出,弹出后下面的所有寄存器都要作相应的调整,例如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FLD Val2 ;ST(0)=4.13 ST(1)=3.14
FSUBRP ST(1),ST(0)
那么,结果是这样计算的:ST(1)=ST(0)-ST(1)=4.13-3.14=0.99并且将ST(0)弹出,然后存放结果的ST(1)以及后续的寄存器就进行调整,那么此时ST(1)就变成ST(0)了,那么最后的结果存入ST(0)中,而原来的ST(0)值4.13则被移出。
(三)、其它数学运算指令
在协处理器中,除了完成具体的数学运算指令外,还设置了若干个与数学运算有关的运算指令。
改变符号:FCHS
这个指令会改变 ST(0)的正负值,如果原先 ST(0)为正值,执行后变为负值;原先为负值,执行后为正值。可以用这个指令计算相反数。
绝对值:FABS
把 ST(0)之值取出,取其绝对值后再存回去。
平方根:FSQRT
将 ST(0)之值取出,开根号后再存回去。
FSCALE 指令
这个指令是计算ST(0)*2ST(1)之值,再把结果存入 ST(0) 里而 ST(1) 之值不变。ST(1) 必须是在 -32768 到 32768 (-215 到 215 )之间的整数,如果超过这个范围计算结果无法确定,如果不是整数 ST(1) 会先向零舍入成整数再计算。所以为安全起见,最好是由整数载入到 ST(1) 里。
FRNDINT 指令
这个指令是把 ST(0) 的数值舍入成整数,FPU 提供四种舍入方式,由 FPU 的控制字组(control word)中的 RC 两个位决定,如下表:
RC |
舍入控制 |
说明 |
例子 |
00 |
四舍五入 |
向最近的整数 |
4.8 → 5.0 -4.8 →-5.0 |
01 |
取小于源数的最大整数 |
正值舍去小数部分 |
4.8 → 4.0 -4.8 →-5.0 |
10 |
取大于源数的最小整数 |
正值舍去小数部分后再加一 |
4.8 → 5.0 -4.8 →-4.0 |
11 |
向零对齐 |
不论正负值均舍去小数部分 |
4.8 → 4.0 -4.8 →-4.0 |
FPREM 指令
这个指令是求余数,较简略的说法是将 ST(0) 除以 ST(1) 后的余数存回 ST,ST(1) 则不变(ST(0)=ST(0)%ST(1))。这个指令实际运作时,是以连续减法的方式求出余数。
FXTRACT 指令
这个指令称为抽取指数与有效数,是把 ST(0) 内的数值改成 X*2Y,然后把 Y 存回 ST(0)里,再把 X 压入堆栈,所以最后 ST(0)为有效数,ST(1) 为以 2 为底的指数。FXTRACT 与 FSCALE 恰好成相反运算。
四.比较运算指令
使用比较指令是将栈顶中的数(ST(0))与其它操作数进行比较,实现条件跳转。所谓条件跳转就是比较两数的大小,如果某数较大,就执行一段程序,若较小则执行另一段程序。在 FPU 的指令集并没有能使 FPU 跳转的指令,事实上 FPU 也无法改变 CPU 寄存器之值 (还记得要改变程序执行地址必须改变 CS:IP 之值),所以要产生 FPU 条件跳转必须用间接方法。其步骤有四个:
先用 FPU 的比较指令改变 FPU 的状态寄存器寄存器。
再用 FPU 的指令 FSTSW 把状态寄存器存入一个内存变量里。
将此内存变量存入 AH 寄存器,再用 CPU 指令 SAHF 指令存入 CPU 的标志寄存器里。此步骤使标志寄存器之值等于FPU状态寄存器。
再用 CPU 指令 JL/JG/JE/JA/JB 来跳转至正确处执行。
状态寄存器
FPU 有五类寄存器,前章已介绍过最常用的堆栈寄存器,这里将介绍状态寄存器(status register)。状态寄存器是一个 16 位的寄存器,表示 FPU 的状态,所谓状态是指 FPU 是不是在忙碌中、是否除以零、是否无效运算、现在堆栈顶端是那一个堆栈寄存器等等,在此处我们要注意的是四个状态码位,C0、C1、C2、C3。这些位分布如下图:
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
B |
C3 |
TOP |
C2 |
C1 |
C0 |
ES |
SF |
PE |
UE |
OE |
ZE |
DE |
IE |
比较指令:FCOM、FCOMP、FCOMPP、FICOM、FICOMP
标题所见的这些比较指令都是以堆栈顶(ST(0))为目的操作数,而源操作数可以是内存变量或是其它的堆栈寄存器,例如:
FCOM ST(0),ST(1)
FCOM ST(0),x
上述第一例是比较 ST(0)和ST(1) 之数值,第二例是比较 ST(0)和内存变量 x 之数值,而这内存变量的形态可以是短实数和长实数。因为 FCOM 等指令均以 ST(0)为目的操作数,所以 ST(0)是可以省略不写的,例如上述两例,可以写成下面的样子,
FCOM ST(1)
FCOM x
结果是一样的。假如 ST(0)的比较对象是 ST(1) 的话(源操作数是ST(1)),连 ST(1) 也可以省略。至于 FCOMP 和 FCOMPP 分别是比较后弹出一次和弹出两次,这里弹出的数会丢失而不会存入内存中,这点和 FSTP 不同。而 FICOM 和 FICOMP 是用来比较整数的,而源操作数可以是字和双字整数,但不能是寄存器,至于目的操作数默认为是ST(0)。
FPU 的比较指令会改变状态寄存器的 C3 和 C0 位,比较后跟据ST(0)和源操作数的大小,设置C3 和 C0标志位如下表所示:
比较结果 |
C3 |
C0 |
ST(0)>源操作数 |
0 |
0 |
ST(0)<源操作数 |
0 |
1 |
ST(0)=源操作数 |
1 |
0 |
ST(0)不可比较 |
1 |
1 |
FSTSW 指令
FSTSW (store status register) 这个指令的功能是把状态寄存器取出并存入内存变量里,而这个内存变量必须是 16 位的内存变量。其语法是:
FSTSW mem16
SAHF 指令
SAHF 是 8088 指令集中的一个指令,并非 FPU 指令。这个指令是把 AH 寄存器中的值移到标志寄存器的较低的 8 个位,这 8 个位只有第七、六、四、二、零位有用,第五、三、一位没有使用。如下图所示:
所以假如 AH 为 0100 0000B,则执行 SAHF 指令后,零标志会被设为一。所以,跳转指令其实是仅仅看标志寄存器的设定值决定如何跳转,至于标志寄存器如何设定(人为还是机器指令运行结果),在跳转指令执行时是不会理会的。
FPU 的状态寄存器里的 C3 和 C0 位,经 FSTSW 指令传到 16 位内存变量,再传到 AX 寄存器里,AH 的第 6和0 位(ZF和CF)就是表示 C3 和 C0 位,再由 SAHF 指令移到标志寄存器,其对应的位是零标志与进位标志,所以只要检查这两个标志就可以比较 ST(0)与源操作数的大小,而决定跳转方向。
FTST和FXAM指令
FTST 栈顶数据ST(0)与0进行比较。
FXAM 检测栈顶数据ST(0)是正数、负数,还是规格化数。
两条指令都是无操作数指令,它们的的比较结果参考C3和C0值的那个表。
五.常数操作指令
FPU 里有 7 个指令是用来把常用的常数压入堆栈顶称为常数指令。这些常数都是内建在 FPU 里的数值,都属于暂时实数,其有效位数达 19 位数,当程序需要用到时可以很快的加载,节省时间与内存。这 7 个常数指令介绍如下:
FLD1 载入 1.0。( 把 1.0 压入堆栈顶 )
FLDZ 载入零。( 把 0.0 压入堆栈顶 )
FLDPI 载入圆周率,3.141592653589793239。( 把 π 压入堆栈顶 )
FLDL2T 载入Log210。(把 Log210压入堆栈顶)
FLDL2E 载入Log2e,e 是自然对数的底数。( 把Log2e压入堆栈顶 )
FLDLG2 载入Log102。( 把Log102压入堆栈顶 )
FLDLN2 载入Loge2,事实上Loge2等于 Ln 2。( 把Loge2压入堆栈顶 )
六.超越函数运算指令
所谓超越函数运算指令是指复杂的函数运算的指令。8087 有五个超越指令,一个用于指数,两个用于自然对数,另外两个用于三角函数的计算。对于 8087 的超越指令所输入的自变量和数学上的自变量不完全相同,例如求 2 的 X 次方,在数学上 X 可以是任意值,但用 8087 计算时 X 却只能在 0 到 0.5 之间,如果要求 2 的任意数次方得用程序来计算。假如在 8087 程序中的自变量超过这个范围,会引起错误但是 8087 却没有检查机制,所以要小心使用。
F2XM1 指令
这个指令是用来计算2ST-1然后将结果存回 ST 里。F2XM1 里的 X 表示 ST 寄存器,M 表示减法之意,它的语法就是:
F2XM1
不含任何操作数。这个指令运算之前还有一个限制,那就是 X 必须是在 0 到 0.5 之间的实数才行,可以等于 0 或 0.5;在 Pentium 等级及其以上,X 可以扩充到在 0 到 1 之间。这个指令之所以要减一的目的是如果 X 很小,则2X会很接近一,减去一可增加有效数。
FYL2X 指令
这个指令是用来计算ST(1)*Log2 ST,这个指令会先弹出 ST 然后以计算的结果取代 ST 寄存器。这个指令的限制是 ST 必须为正数。
FYL2XP1 指令
这个指令是计算ST*Log2( ST(1)+1 ),这个指令会先弹出 ST 然后以计算的结果取代 ST 寄存器,ST(1) 必须是大于零且小于二分之根号二的数。这个指令在 Log 后的数很接近一时,比 FYL2X 有较好的准确度。
FPTAN 指令
这个指令用来计算 tan(ST) 之结果,而计算结果是以分数 Y/X 的形式存入堆栈,计算后先把 tan(ST)之值压入堆栈(当作 Y 值),再把 1 (当作 X 值)压入堆栈,换句话说最后的结果是ST(1)为tan(ST),ST为1。在8087等级的FPU运算时,计算前ST必须是0~π/4;如果在 Pentium 等级及其以上的 CPU,除了计算前ST须以弧度表示外,似乎没有范围限制。
FPATAN 指令
这个指令是用来计算 arctan ( ST(1)/ST ) 的,然后把计算结果以弧度表示存入ST。整个计算过程是先弹出堆栈顶当做分母(X),再弹出新的堆栈顶(也就是原来的ST(1) )当做分子,计算Y/X之反正切函数,再把计算结果存回堆栈顶。如果是在 8087 FPU 上运算,计算前 ST 与 ST(1) 必须为正值,而在 Pentium 及其以上的 CPU 则无此限制。
在 80387 等级及其以上的 FPU 还提供的更多的超越函数:
FSIN 指令
这是用来计算堆栈顶的正弦函数 (sin),再把结果压入堆栈顶,计算前堆栈顶没有范围的限制,但要使用弧度,80387 等级及其以上的 FPU 才提供这个指令。
FCOS 指令
这是用来计算堆栈顶的余弦函数 (cos),再把结果压入堆栈顶,计算前堆栈顶没有范围的限制,但要使用弧度,80387 等级及其以上的 FPU 才提供这个指令。
FSINCOS 指令
这个指令只有在 80387 等级及其以上的 FPU 才提供,它会弹出堆栈顶然后计算 sin ST 与 cos ST 之值,然后把 sin ST 之结果压入堆栈寄存器,再把 con ST 之结果压入堆栈寄存器,所以堆栈顶为余弦值, ST(1) 为正弦值。
七.协处理器控制指令
协处理器控制指令是用来控制协处理器状态而设置的,它包括协处理器的初始化、状态寄存器内容的存取、异常处理和任务切换等操作。
FINIT/FNINIT
初始化协处理器,初始化后协处理器的状态如下表所示:
协处理器初始化的状态
控制项 |
值 |
状态含义 |
控制位IC |
0 |
投影 |
控制位PC |
10 |
扩展精度 |
控制位RC |
00 |
最近舍入或偶数 |
错误屏蔽 |
11111 |
错误位关闭 |
忙标志 |
0 |
不忙 |
C3~C0 |
???? |
未定 |
TOP |
000 |
堆栈栈顶设定为寄存器0 |
ES |
0 |
无错误 |
错误位 |
00000 |
无错误 |
全部标记 |
11 |
空 |
寄存器 |
-- |
不改变 |
FLDCW Mem16
将由操作数指定的字存储单元内容存储到控制寄存器中。
FSTCW/ FNSTCW Mem16
把控制寄存器的内容存储到由操作数指定的字存储单元。与指令“FLDCW”相对应。
FSTSW Mem16
FSTSW AX
FNSTSW Mem16
FNSTSW AX
将控制寄存器的内容传送到寄存器AX中。在8087协处理器中无此指令。
FCLEX/FNCLEX
清除状态寄存器中的“错误”和“忙”标志。
FSAVE Mem
FNSAVE Mem
将全部机器状态存储到内存中。
FRSTOR Mem
从内存复原机器状态,它可恢复由指令“FSAVE/FNSAVE”保存的信息。
FSTENV Mem
FNSTENVMem
存储协处理器环境。
FLDENV Mem
重新装入由指令FSTENV/FNSTENV存储的协处理器环境。
FINCST
堆栈指针加1。
FDECSTP
堆栈指针减1。
FFREE ST(i)
释放堆栈寄存器,即使其标记为空,但其内容并没有改变。
FNOP
协处理器的空操作
FWAIT
使处理器处于等待状态,以便协处理器完成其操作。该指令主要用于在CPU访问被协处理器影响的内存数据之前。