📄 汇011.txt
字号:
例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
11.2.3 控制寄存器
控制寄存器主要用于浮点数精度选择的控制、四舍五入的控制和无穷大的控制等,其低6位还可用来决定是否屏蔽协处理器的异常。指令FLDCW可用来设置控制寄存器的值。控制寄存器中控制位的分布如图11.6所示,其控制位的含义如表11.3所列。
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
IC
RC
PC PM UM OM ZM DM IM
图11.6 控制寄存器的控制位分布示意图
表11.3 控制寄存器中控制位的含义
控制位 控制功能说明
IC(无穷大控制) 0—投影,假定是无符号无穷;
1—仿射,允许正、负无穷
RC(舍入控制) 00—最接近或偶数,01—舍入成负无穷,
11—舍入成负无穷,10—截成0
PC(精度控制) 00—单精度,01—保留,11—双精度,10—扩展精度
PM 精度错误屏蔽位
若屏蔽位的值为1,则状态寄存器的相应位被屏蔽。
UM 下溢出屏蔽位
OM 上溢出屏蔽位
ZM 除数为0屏蔽位
DM 非规格化操作数屏蔽位
IM 非法操作屏蔽位
11.2.4 标记寄存器
标记寄存器用来表明协处理器堆栈中各存储单元内容的状态,也就是说,该寄存器可表明堆栈中的数据是合法的,还是非法的,是无穷,还是0或空等。该标记寄存器的结构如图11.7所示。
15 13 11 9 7 5 3 1 0
TAG(7) TAG(6) TAG(5) TAG(4) TAG(3) TAG(2) TAG(1) TAG(0)
图11.7 标记寄存器结构示意图
其中:TAG(i)的取值含义:00—合法,01—0,10—非法或无穷,11—空
在协处理器中,查看标记寄存器的方法是使用指令FSTENV、FSAVE或FRSTOR,它们都能使标记寄存器与其它协处理器数据一起转存。
11.3 协处理器的指令系统
协处理器共有68条不同的指令,汇编程序在遇到协处理器指令助忆时,都会将其转换成机器语言的ESC指令,ESC指令代表了协处理器的操作码。
在协处理器指令在执行过程中,需要访问内存单元时,CPU会为其形成内存地址。协处理器在协处理器指令期间内利用数据总线来传递数据。80287协处理器利用I/O地址00FAH~00FFH来实现其与CPU之间的数据交换,而80387~Pentium系列芯片,则是利用I/O地址800000FAH~800000FFH来实现这两者之间的数据交换。
11.3.1 指令操作符的命名规则
协处理器指令的操作符(或助忆符)在命名设计时,遵循了下列规则:
1、在操作符后面加上字母P:表示该指令执行完后,还进行一次堆栈弹出操作。如:FADD和FADDP等;
2、在操作符后面加上字母R:表示该操作是反模式,它仅限于减法、除法指令。如:FSUB和FSUBR等;
正模式 —— 栈顶数据=栈顶数据 op 指令操作数,或OPN1=OPN1 – OPN2
反模式 —— 栈顶数据=指令操作数 op 栈顶数据,或OPN1=OPN2 – OPN1
假设:栈顶数据为10,内存变量data的值为1,分别执行下列指令将有不同的结果。
FSUB data ;指令执行后,栈顶数据为9
FSUBR data ;指令执行后,栈顶数据为-9
FSUB ST, ST(1) ;指令执行后,ST=ST-ST(1)
FSUBR ST, ST(1) ;指令执行后,ST=ST(1)-ST
3、操作符的第2个字母是I:表示内存中数据是整数。它对加、减、乘除指令都有效。
例如:FADD data——浮点数加法;
FIADD data——整数加法,它表示内存单元data是一个整数,把该整数加到栈顶的浮点数上。
4、操作符的第2个字母是N:表示在指令执行之前检查非屏蔽数值性错误。如:FSAVE和FNSAVE等,前者称为等待形式(wait version),后者称为非等待形式(no-wait version)。
在使用.8087伪指令情况下,汇编程序会在等待形式的指令前面加上指令WAIT,而在非等待形式的指令前面加上空操作指令NOP。
理解了上述操作符命名规则,就能很容易地区分同类指令之间的差异。
11.3.2 数据传送指令
为了满足协处理器和CPU之间进行数据交流的需求,就需要实现内存单元和协处理器之间进行数据传送的指令。协处理器的指令系统中有三大类数据传送指令:BCD传送指令、浮点数传送和整数传送指令。
一、BCD传送指令
1、FBLD
指令格式:FBLD MemBCD(*)
指令功能:将内存中的BCD数据压入协处理器的堆栈中;
(*) MemType是指定数据类型Type的内存单元,如:MemBCD是BCD类型的存储单元。此后不再说明。
2、FBSTP
指令格式:FBSTP MemBCD
指令功能:将协处理器中的BCD数据存入内存,并进行堆栈的弹出操作。
例如:
.387
data1 DT 123, -543
data2 DT 2.5
……
FBLD data1 ;把BCD数据123压进栈
FBSTP data2 ;把当前堆顶数据弹出,并传送给BCD型的内参单元
二、浮点数传送指令
1、FLD
指令格式: FLD STReg(*)/MemReal
指令功能: 将浮点数据压入协处理器的堆栈中。当进行内存单元内容压栈时,系统会自动决定传送数据的精度。比如:用DD或REAL4定义的内存单元数值是单精度数等。
(*) STReg是协处理器堆栈寄存器ST(0)~ST(7)。
例如:
.387
data1 DD 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执行完后,则需要进行堆栈的弹出操作,堆栈将发生变化。请见11.3.1节中的指令操作符命名规则的说明。
4、FXCH
指令格式: FXCH [STReg]
指令功能: 将指定的寄存器中的浮点数与堆顶浮点数进行交换。如果不指定操作数,那么,默认ST和ST(1)二者之间交换数据。
例如:FXCH ST(2)——栈顶数据与堆栈寄存器ST(2)进行数据交换。
三、整数传送指令
1、FILD
指令格式:FILD MemInt
其中:MemInt是定义为整型数据类型的内存单元,但不能是用DB定义的存储单元。下同,不再叙述。
2、FIST/FISTP
指令格式: FIST MemInt
FISTP MemInt
其中: Mem是定义整型数据类型的内存单元,但不能是用DB定义的存储单元。
指令功能: 将协处理器堆栈栈顶的数据传送到目标存储单元中。在进行数据传送时,系统自动根据控制寄存器中舍入控制位的设置把栈顶浮点数舍入成整型数据。
指令FIST和FISTP的区别在于堆栈操作,详细请见11.3.1中的命名规则说明。
11.3.3 数学运算指令
在协处理器的指令系统中,有关数学运算指令有:加法指令、减法指令、乘法指令、除法指令和求平方根指令等。涉及数学运算的指令有比例运算、舍入运算、求绝对值运算和改变数值符号运算等指令。
1、加法指令
指令格式: FADD [STReg1, STReg2](*)
FADD MemReal
FADDP STReg, ST
FIADD MemInt
(*) 在此指令格式下,如果同时指定了二个堆栈寄存器,那么,其中一个寄存器必须是ST。其它指令的同类格式与此同理。
指令FADD含有二个隐含操作数ST(1)和ST,其运算功能是:从堆栈中弹出这二个操作数,然后把计算的“和”压入堆栈,即:ST=ST(1)+ST。
指令“FADD MemReal”的功能:ST=ST+MemReal
指令“FADDP STReg, ST”的功能:STReg=STReg+ST,并弹出堆栈的栈顶
指令“FIADD MemInt”的功能:ST=ST+MemInt
2、减法指令
指令格式: FSUB [STReg1, STReg2]
FSUB MemReal
FSUBP STReg, ST
FISUB MemInt
FSUBR [STReg1, STReg2] ;后四条指令是前四条指令的反模式形式
FSUBR MemReal
FSUBRP STReg,ST
FISUBR MemInt
指令FSUB含有二个隐含操作数ST(1)和ST,其运算功能是:从堆栈中弹出这二个操作数,然后把计算的“差”压入堆栈,即:ST=ST(1)-ST。
指令“FSUB MemReal”的功能:ST=ST-MemReal
指令“FSUBP STReg, ST”的功能:STReg=STReg-ST,并弹出堆栈的栈顶
指令“FISUB MemInt”的功能:ST=ST-MemInt
反模式的四条指令的功能在此从略,请参阅11.3.1中的有关说明。
3、乘法指令
指令格式: FMUL [STReg1, STReg2]
FMUL MemReal
FMULP STReg, ST
FIMUL MemInt
4、除法指令
指令格式: FDIV [STReg1, STReg2]
FDIV MemReal
FDIVP STReg, ST
FIDIV MemInt
FDIVR [STReg1, STReg2] ;后四条指令是前四条指令的反模式形式
FDIVR MemReal
FDIVRP STReg, ST
FIDIVR MemInt
例如:
.387
word1 DW 20
data1 REAL8 8
data2 REAL8 -2
data3 REAL8 -12
……
FLD data1 ;本例只是显示指令的使用方法,无具体的实际功能
FLD data2
FLD data3
FDIV ST(2), ST
FDIV data1
FDIVP ST(2), ST
FIDIV word1
5、其它数学运算指令
在协处理器中,除了完成具体的数学运算指令外,还设置了若干个与数学运算有关的运算指令。具体的运算指令及其功能描述如表11.4所列。
表11.4 与数学运算有关的其它指令
指令格式
指令的功能
FSQRT
求栈顶数据的平方根。如果对负数求其平方根,则会发生错误,并可通过检测状态寄存器的标志位IE来确定。
FSCALE
将ST(1)中的数(转换成整数)加上ST的阶码,该指令能快速完成乘/除2n的运算。ST(1)中的数必须在2-15到215之间。
FPREM/FPREM1
ST=ST%ST(1),80387及其以后的协处理器支持FPREM1。
FRNDINT
对栈顶数据进行舍入运算,使之转换成整数。
FXTRACT
将栈顶数据分成二部分:无偏阶码和尾数。尾数存入栈顶,无偏阶码存入ST(1)。它常用将浮点数转换成小数形式打印输出。
FABS
ST=|ST|,即:求栈顶数据的绝对值。
FCHS
ST=-ST,即:改变栈顶数据的符号。
11.3.4 比较运算指令
使用比较指令是将栈顶中的数与其它操作数进行比较,比较结果存于状态寄存器的条件编码位C3~C0处(参阅表11.2)。具体的比较运算指令及其功能描述如表11.5所列。
表11.5 比较运算指令及其功能
指令格式
指令的功能
FCOM
将栈顶数据与另一个操作数进行比较,该操作数可以存储在堆栈寄存器中,也可存储在内存中。
当在指令中不指定操作数时,其默认的操作数是ST和ST(1)。
FCOMP/FCOMPP
此指令的比较功能与FCOM相一致,所不同的是指出从堆栈中弹出一个,还是二个数据。
FICOM MemInt
FICOMP MemInt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -