1.栈式浮点累加器

在浮点指令执行过程中,8个80位长度的物理寄存器组被作为栈式累加器使用。虽然每个80位寄存器有固定的物理顺序位置(即左边的0~7),但当前栈顶则由ST(即ST(0))来指明。ST之下的其余累加器使用名称ST(i)来指明(i = 1~7)。至于哪个80位物理寄存器是当前栈顶ST,则由具体操作过程指定。在状态字寄存器中名称为TOP的3位字段含有当前栈顶ST对应的80位物理寄存器的绝对位置。一个入栈(Push)操作将会把TOP字段值递减1,并把新值存储于新的ST中。在入栈操作之后,原来的ST变成了ST(1),而原来的ST(7)变成了现在的ST。即所有累加器的名称都从原来的ST(i)变成了ST((i+1)&0x7)。一个出栈(Pop)操作将会读出当前ST对应的80位寄存器的值,并且把TOP字段值递增1。因此在出栈操作之后,原来的ST(即ST(0))变成了ST(7),原来的ST(1)成为新的ST。即所有累加器的名称都从原来的ST(i)变成ST((i-1)& 0x7)。

ST的作用如同一个累加器是因为它被作为所有浮点指令的一个隐含操作数。若有另一个操作数,那么该第2个操作数可以是任何其余累加器之一ST(i),或者是一个内存操作数。栈中的每个累加器为一个实数提供了使用临时实数格式存储的80位空间,其最高位(s)是符号位,位78~64是15位的指数字段,位63~0是64位的有效数字段。

浮点指令被设计成能充分利用这个累加器栈模式。浮点加载指令(FLD等)会从内存中读取一个操作数并压入栈中,而浮点存储指令则会从当前栈顶取得一个值并写到内存中。若栈中该值不再需要时还可以同时执行出栈操作。加和乘之类的操作会把当前ST寄存器内容作为一个操作数,而另一个取自其他寄存器或内存中,并且在计算完后即把结果保存在ST中。还有一类“操作并弹出”操作形式用于在ST和ST(1)两者之间进行运算。这种操作形式会执行一次弹出操作,然后把结果放入新的ST中。

2.状态与控制寄存器

三个16位的寄存器(TAG字、控制字和状态字)控制着浮点指令的操作并且为其提供状态信息。它们的具体格式如图11-6所示。下面逐一对它们进行说明。

(1)控制字

控制字(Control Word)可用于程序设置各种处理选项来控制80387的操作。其中可分为三个部分。位11~10的RC(Rounding Control)是舍入控制字段,用于对计算结果进行舍入操作。位9~8的PC(Precision Control)是精度控制字段,用于在保存到指定存储单元之前对计算结果进行精度调整。所有其他操作使用临时实数格式精度,或者使用指令指定的精度。位5~0是异常屏蔽位,用于控制协处理器异常处理。这6位对应80387可能发生的6种异常情况。其中每一种异常都可以单独屏蔽掉。如果发生某个特定异常并且其对应屏蔽位没有置位,那么80387就会向CPU通报这个异常,并且会让CPU产生异常中断int 16。然而如果设置了对应屏蔽位,那么80387就会自己处理并纠正发生的异常问题而不会通知CPU。这个寄存器随时可以读写,其中各位的具体含义参见图11-6。

(2)状态字

在运行期间,80387会设置状态字(Status Word)中的位,用于程序检测特定的条件。当发生异常时,它可让CPU确定发生异常的原因。因为所有6个协处理器异常都会让CPU产生异常中断int16。

(3)特征字

特征字(Tag Word)寄存器含有8个2位的Tag字段,分别对应8个物理浮点数据寄存器。这些特征字段分别指明相应的物理寄存器含有有效、零、特殊浮点数值,或者是空的。特殊数值是指那些无限值、非数值、非规格化或不支持格式的数值。特征字段Tag可用于检测累加器堆栈上下溢出情况。如果入栈(Push)操作递减TOP指向了一个非空寄存器,就会发生栈上溢出。如果出栈(Pop)操作企图去读取或弹出空寄存器,就会造成栈下溢出(Underflow)。栈的上下溢出都将引发无效操作异常。

Linux内核完全剖析---数学协处理器1)



相关内容