设为首页 加入收藏

TOP

8.3.3 指令使用
2013-10-07 00:53:22 来源: 作者: 【 】 浏览:64
Tags:8.3.3 指令 使用

8.3.3  指令使用

(1)设备初始化

初始化硬件只有一条指令FINIT,执行FINIT指令之后,x87 FPU硬件复位。控制寄存器值是0x037F,即所有异常被屏蔽、最近舍入、64位运算精度。状态寄存器清零,即没有异常、堆栈指针是0。标志寄存器是0xFFFF,即8个数据寄存器全空,没有有效数据,但实际上,8个数据寄存器的内容没有改变。FINIT指令在复位硬件前会检查状态寄存器中的异常状态纪录,如果有异常发生且控制寄存器没有屏蔽该异常则触发该异常,FNINIT指令完成与FINIT一样的初始化功能,但不进行异常检测。

(2)系统设置

FINIT指令实际上已经进行了默认设置,不过,它的设置可能不符合你的需要。x87 FPU的设置一般有三个方面:异常处理、计算精度和舍入模式,实际上就是控制寄存器的设置。

状态寄存器和标志寄存器是只读的,一般不能改写,但可以通过特殊途径(FSAVE和FRSTOR指令)改写。

(3)计算

计算过程中需要特别注意的是浮点堆栈。由于浮点堆栈不用于程序控制,出了问题以后不会立即表现出来,即使表现出来也不一定会导致程序崩溃,因此相当隐秘。在C/C++(www.cppentry.com)等高级语言编程(www.cppentry.com)过程中,编译器处理了这个问题,但在汇编语言中需要自己处理这个问题。

在代码编写过程中,要清楚自己使用的数据寄存器的值及个数,一旦不需要就及时清空。数据寄存器只有8个,因此除非做好了详细计划,一般不要使用它们长期存储数据。减少寄存器使用个数的关键在于挑选合适的指令并且安排好指令序列,尽量减少中间结果的个数。例如实现a+b+c的代码可以是:

  1. FLD a  
  2. FLD b  
  3. FLd c  
  4. FADDP ST(1), ST(0)  
  5. FADDP ST(1), ST(0) 

最多使用了3个数据寄存器。若换个形式:

  1. FLD a  
  2. FADD b  
  3. FADD c 

只使用了1个数据寄存器。

(4)设备信息的维护

现代操作系统多是多用户系统,有多任务(进程或线程)调度功能,用户任务经常被切换。假设任务A正在进行浮点运算,x87 FPU正在执行一个指令序列,此时发生了线程切换,线程B取代线程A获得了对x87 FPU的控制,线程B自然也可能使用x87 FPU,那么显然线程A的中间结果(正在数据寄存器堆栈中)和设置将被破坏。当线程A再度获得对x87 FPU的控制时,此时的x87 FPU已是线程B使用时的状态,线程A的计算将出现错误。同样,线程B也是一团糟。这个问题实际上是个简单的信息共享问题,解决之道就是在任务切换时进行信息的保存和恢复,从而使各任务的信息互不干扰。x87 FPU为了支持这一功能,提供了两条指令,即FSAVE指令和FRSTOR指令。

当任务被挂起时,操作系统任务调度模块使用FSAVE指令将x87 FPU保存于任务数据块中。当任务被恢复时,使用FRSTOR指令将FSAVE指令保存的数据载入x87 FPU。如此,计算将不受任务切换的影响。

如果你想自己处理浮点异常,那么就需要熟悉FSAVE指令保存的信息格式,因为在Windows中,当异常发生时,内核正是通过FSAVE指令将x87 FPU的信息保存起来传递给异常处理代码。当然,在这个层次处理异常通常是操作系统和浮点库的任务。除非你想创建一个浮点库并且该浮点库完善到自己进行异常处理,否则你不需要熟悉FSAVE指令和FRSTOR指令。

【责任编辑:董书 TEL:(010)68476606】

回书目   上一节   下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇8.3.2 指令分类(1) 下一篇8.3.1 指令简介

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: