首页 > 汇编语言 > 浮点数处理与指令编码
阅读:2,242
汇编语言FWAIT(WAIT)指令:异常同步
整数 (CPU) 和 FPU 是相互独立的单元,因此,在执行整数和系统指令的同时可以执行浮点指令。这个功能被称为并行性 (concurrency),当发生未屏蔽的浮点异常时,它可能是个潜在的问题。反之,已屏蔽异常则不成问题,因为,FPU 总是可以完成当前操作并保存结果。
发生未屏蔽异常时,中断当前的浮点指令,FPU 发异常事件信号。当下一条浮点指令或 FWAIT(WAIT) 指令将要执行时,FPU 检查待处理的异常。如果发现有这样的异常,FPU 就调用浮点异常处理程序(子程序)。
如果引发异常的浮点指令后面跟的是整数或系统指令,情况又会是怎样的呢?很遗憾,指令不会检查待处理异常,它们会立即执行。假设第一条指令将其输出送入一个内存操作数,而第二条指令又要修改同一个内存操作数,那么异常处理程序就不能正确执行。示例如下:
发生未屏蔽异常时,中断当前的浮点指令,FPU 发异常事件信号。当下一条浮点指令或 FWAIT(WAIT) 指令将要执行时,FPU 检查待处理的异常。如果发现有这样的异常,FPU 就调用浮点异常处理程序(子程序)。
如果引发异常的浮点指令后面跟的是整数或系统指令,情况又会是怎样的呢?很遗憾,指令不会检查待处理异常,它们会立即执行。假设第一条指令将其输出送入一个内存操作数,而第二条指令又要修改同一个内存操作数,那么异常处理程序就不能正确执行。示例如下:
.data
intVal DWORD 25
.code
fild intVal ;将整数加载到 ST(0)
inc intVal ;整数加 1
fild intVal ;将整数加载到 ST(0)
fwait ;等待待处理异常
inc intVal ;整数加 1
表达式
现在编写代码,计算表达式 valD=-valA+(valB*valC)。下面给出一种可能的循序渐进的方法:将 valA 加载到堆栈,并取其负数;将 valB 加载到 ST(0),则 valA 成为 ST(1);将 ST(0) 和 valC 相乘,乘积保存在 ST(0) 中;将 ST(1) 与 ST(0) 相加,和数保存到 valD:.data valA REAL8 1.5 valB REAL8 2.5 valC REAL8 3.0 valD REAL8 ?; +6.0 .code fld valA ; ST(0) = valA fchs ;修改 ST(0) 的符号 fld valB ; 将 valB 加载到 ST(0) fmul valC ; ST(0) *= valC fadd ; ST(0) += ST(1) fstp valD ; 将 ST(0) 保存到 valD
数组求和
下面的代码计算并显示一个双精度实数数组之和:ARRAY_SIZE = 20 .data sngArray REAL8 ARRAY_SIZE DUP(?) .code mov esi, 0 ;数组索引 fldz ; 0.0 入栈 mov ecx,ARRAY_SIZE L1: fld sngArray[esi] ;将内存操作数加载到ST(0) fadd ; ST(0) 加 ST(1),出栈 add esi,TYPE REAL8 ;移至!I 下一个元素 loop L1 call WriteFloat ;显示 ST(0) 中的和数
平方根之和
FSQRT 指令对 ST(0) 中的数值求平方根,并将结果送回 ST(0)。下面的代码计算了两个数的平方根之和:.data valA REAL8 25.0 valB REAL8 36.0 .code fid valA ; valA 入栈 fsqrt ; ST(0) = sqrt(valA) fid valB ; valB 入栈 fsqrt ; ST(0) = sqrt(valB) fadd ; ST (0)+ST(1)
数组点积
下面的代码计算了表达式 (airay[0]*airay[l]) + (array[2]*array[3])。该计算有时也被称为点积 (dot product)。
.data
array REAL4 6.0, 2.0, 4.5, 3.2
指令 | FPU堆栈 | 指令 | FPU堆栈 |
---|---|---|---|
fld array | ST(0):+6.0000000E+000 | fmul [array+12] | ST(0):+1.4400000E+001 |
fmul [array+4] | ST(0):+1.2000000E+001 | ST(1):+1.2000000E+001 | |
fld [array+8] | ST(0):+4.5000000E+000 | fadd | ST(0):+2.6400000E+001 |
ST(1):+1.2000000E+001 |