Intel 8087浮点芯片内部的微码:寄存器交换
摘要
对Intel 8087浮点协处理器内部微码的详细逆向工程分析,聚焦于FXCH寄存器交换指令及芯片内部架构。
暂无内容
查看缓存全文
缓存时间: 2026/05/30 19:28
# Intel 8087 浮点芯片内部的微码:寄存器交换
来源:https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html
1980 年,Intel 推出了 8087 浮点芯片,这是一款协处理器,能让浮点运算速度提升 100 倍。该芯片影响深远,如今大多数处理器都采用 8087 引入的浮点标准。
8087 使用复杂的算法来精确计算平方根、正切和指数等函数。这些算法在芯片内部通过名为微码的低层代码实现。我是 Opcode Collective 小组的一员,正在逆向分析这些微码。在本文中,我将深入剖析 8087 指令之一——`FXCH` 的微码,并解释其工作原理。`FXCH`(浮点交换)指令用于交换两个浮点寄存器。你可能认为这条指令微不足道,但实际情况比想象的要复杂:微码用了 14 条微指令来实现这次交换操作。
Intel 8087 芯片封装在 40 引脚 DIP(双列直插式)中。(https://static.righto.com/images/8087-fxch/8087-package.jpg)
Intel 8087 芯片封装在 40 引脚 DIP(双列直插式)中。
为了探索微码,我打开了一片 8087 芯片,并用显微镜生成了高分辨率图像。巨大的微码 ROM 位于中央位置,其中保存着控制芯片的微指令。左侧的微码引擎负责逐条执行微码,处理跳转和子程序调用。芯片下半部分是“数据路径”,即执行浮点运算的电路;它被分为 16 位的数据路径(用于处理数字的指数)和 64 位的数据路径(用于处理数字的小数部分,也称为有效数字)。
Intel 8087 浮点单元芯片裸片,主要功能模块已标注。裸片尺寸为 5mm×6mm。点击查看大图。(https://static.righto.com/images/8087-fxch/8087-die-labeled.jpg)
Intel 8087 浮点单元芯片裸片,主要功能模块已标注。裸片尺寸为 5mm×6mm。点击查看大图。
本文重点关注以红色高亮显示的临时寄存器和栈寄存器。芯片有两个临时寄存器和八个栈寄存器,每个寄存器都保存着一个数字的指数和小数部分。每个寄存器还有两个标签位,用于标记该寄存器中值的类型。右侧的[栈控制电路](https://www.righto.com/2025/12/8087-stack-circuitry.html)负责管理栈,跟踪栈顶位置,以便在压栈或出栈时进行更新。
执行 8087 指令(如反正切)需要数百个内部步骤来计算结果。这些步骤通过微码实现,微指令指定算法的每个步骤。(请注意指令的两个层次:程序员使用的汇编语言指令和芯片内部未公开的低层微指令。)微码 ROM 包含 1648 条微指令,实现了 8087 的指令集。每条微指令长 16 位,执行诸如在芯片内部移动数据、两个值相加或[移位](https://www.righto.com/2020/05/die-analysis-of-8087-math-coprocessors.html)等简单操作。我正在与 Opcode Collective 合作,逆向分析这些微指令并全面理解微码(链接(https://github.com/a-mcego/granite/blob/main/tools/8087mc/bin/8087.md))。
8087 的微指令相当复杂,涉及许多边界情况和专用功能,但我会提供一个简化的概述。每条微指令由 16 位组成,如下所示。前三位指定微指令的类型,这决定了其余位的含义。第一种类型表示传输操作,即将数据从一个内部寄存器传输到另一个。两个字段分别指定源和目标。未指定的三位用于各种特殊情形。接下来是移位操作,利用桶形移位器将值左移或右移。第三种类型的微指令使用加法器/减法器,也可用于乘法或除法的循环中。第四种是各种算术控制微指令,用于配置加法器、设置舍入模式等。远跳转和远调用微指令用于跳转到或调用固定列表中的目标微地址。条件字段允许基于多种[条件](https://www.righto.com/2025/12/8087-microcode-conditions.html)进行条件跳转/调用,最后一位用于反转条件。本地跳转则允许条件跳转到附近的微指令。最后,杂项微指令包括从子程序返回、引发异常或结束微码执行。
8087 微指令的结构。(https://static.righto.com/images/8087-fxch/microcode-structure.jpg)
8087 微指令的结构。
## 数值在 8087 芯片内部的存储方式
8087 支持多种数据类型:各种尺寸的浮点数、整数以及二进制编码十进制数。但芯片内部所有数据都以 80 位浮点数的形式存储。一个数包含三个部分:64 位有效数字(小数部分)、15 位指数和一个符号位。芯片有两条独立的数据路径:一条用于有效数字,另一条用于指数和符号。
芯片有八个寄存器用于在计算过程中存储数字,如下方顶部图所示。然而,这些寄存器以一种不寻常的方式组织:作为栈来使用,数字被压入栈或从栈中弹出。你并非直接访问例如 3 号寄存器,而是访问栈顶起的第三个寄存器,记作 `ST(3)`;当值被压入或弹出时,`ST(3)` 会随之改变。这种基于栈的架构旨在改进指令集、简化编译器设计并使函数调用更高效,尽管实际效果并不如预期。
程序员视角下 8087 的寄存器组。来自《8086 系列数值运算增刊》。(https://static.righto.com/images/8087-fxch/register-set.jpg)
许多 8087 指令作用于栈顶。例如,平方根指令将栈顶的值替换为其平方根。但如果想对栈中间的值求平方根呢?解决方案就是 `FXCH` 指令,这也是本文的重点。该指令将栈顶的值与指定的栈位置交换,从而可以访问栈内部的值。
8087 还有一个对本文重要的特性:寄存器栈中的每个值都有一个关联的“标签”值,用于标记该值为有效、特殊、零或空。“正常”的浮点值被标记为 *valid*。如果浮点值是无穷大、非数 (NaN) 或非规格化数,则被标记为 *special*。零值被标记为 *zero*。最后,如果寄存器为空(例如,其值已从栈中弹出),则该寄存器被标记为 *empty*。8087 利用标签来优化性能并检测错误。¹(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:tags)例如,如果程序员从栈中弹出过多值,并试图读取一个标记为空的栈寄存器,8087 就会引发“无效操作”异常。
八个栈寄存器对程序员可见,但 8087 内部也使用临时寄存器。有两个临时寄存器对本文很重要:`tmpA` 和 `tmpB`。与栈寄存器一样,每个临时寄存器也是一个 80 位寄存器,外加两个标签位。
## `FXCH` 微码
在本节中,我将解释 `FXCH` 交换指令的微码工作原理。该指令将栈顶寄存器与栈中指定位置的寄存器进行交换。如果任一寄存器为空,该指令将引发“无效操作”异常,并用特殊值“非数”(NaN) 替换缺失的值。
该指令的微码如下,由 14 条微指令组成。²(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:microcode)第一条微指令是传输操作,源是栈顶值 `ST(0)`,目标是临时 A 寄存器。源指定会导致 64 位有效数字被放置到小数总线上,16 位指数和符号被放置到指数总线上,两个标签位被发送到标签电路。目标 `tmpA` 会导致总线上的值被存储到临时寄存器中。因此,微指令中的这些位就实现了所需的传输。第三条微指令类似,但使用的是栈内的寄存器 `ST(i)`,其索引由机器指令指定。
```
FXCH 入口点:
#0200 ST(0) -> tmpA 读取栈顶
#0201 nop 等待一个周期
#0202 ST(i) -> tmpB 读取指定的栈寄存器
#0203 if !(tmpA 或 tmpB 为空) jmp #0210 如果两个寄存器都存在则跳转
#0204 set invalid exception 设置无效异常
#0205 if (未屏蔽) jmp #0213 如果中断发生则结束
#0206 if !(tmpA 为空) jmp #0208 检查 tmpA 是否为空
#0207 NaN -> tmpA 如果是,则将 NaN 移到 tmpA
#0208 if !(tmpB 为空) jmp #0210 检查 tmpB 是否为空
#0209 NaN -> tmpB 如果是,则将 NaN 移到 tmpB
正常路径与错误路径在此汇合:
#0210 tmpB -> ST(0) 将 tmpB 保存到栈顶
#0211 nop 等待一个周期
#0212 tmpA -> ST(i) 将 tmpA 保存到指定的栈寄存器
#0213 RNI 例程结束:运行下一条指令
#0214 nop 未使用
#0215 nop 未使用
#0216 nop 未使用
```
接下来,位于微地址 `#0203` 的相对跳转展示了另一种类型的微指令:条件跳转。该微指令指定了一个条件,在本例中是测试任一临时寄存器是否为空。(即,硬件测试与临时寄存器关联的标签位,看是否有标签为“空”。)微指令中有一个位用于反转条件。最后,该微指令有一个偏移量 +6,得出跳转目标 `#0210`。使用相对偏移量而不是指定完整微地址的好处是偏移量只需 6 位。(有关条件如何求值的更多信息,请参阅我的文章 [Intel 8087 浮点芯片微码中的条件](https://www.righto.com/2025/12/8087-microcode-conditions.html)。)
如果任一寄存器为空,则下一条微指令会引发“invalid”异常。正如我将在下一节解释的,你可以对 8087 进行编程,使其在异常发生时产生中断,或者继续处理。下一条指令是一个条件跳转,测试异常是否“未屏蔽”,即是否产生了中断。在这种情况下,微码结束,由主 8086 处理器处理中断。
假设中断被屏蔽,微码现在会用特殊的“非数”值替换空值,首先检查 `tmpA`,然后检查 `tmpB`。源 `NaN` 会使电路将指数总线全部拉高,小数总线除顶部位外全部拉低。这个特定的位模式就表示非数。³(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:nan)
在微地址 `#0210` 处,空寄存器路径和正常路径汇合,将临时寄存器保存到栈寄存器中。这就是实际的交换操作发生的位置,因为 `tmpA` 和 `tmpB` 被写入与读取时相反的栈位置。最后,`RNI`(运行下一条指令)表示微码例程结束。这会停止微码引擎,使 8087 准备好执行下一条指令。
`nop`(空操作)微指令很有意思。每组栈读取或写入的中间都有一个 `nop`,这可能是寄存器的时序限制导致的。微码例程的末尾有三个 `nop` 指令,之后才开始下一个微码例程。这些指令看起来像是微码中的浪费空间;也许 `FXCH` 微码在开发过程中被缩短了三个字,从而造成了这个空隙。
## 异常
8087 有一个复杂的异常系统来处理各种问题。异常分为六类:无效操作、非规格化操作、除零、溢出、下溢或精度。例如,如果对负数开平方或试图对空寄存器执行操作,就会发生无效操作异常。溢出异常发生在数值太大而无法表示时,下溢异常则发生在数值太小而无法表示时。除零异常发生在除以零时。⁴(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:zero)精度异常发生在数字无法精确表示为浮点数时(这种情况极为常见)。最后,当数值太接近零而无法用完全精度表示时,会发生非规格化异常。
异常发生时会发生什么?8087 允许程序员为每种异常类型选择异常行为。第一种选项是异常触发 CPU 中断,以便软件处理问题。例如,软件可以尝试绕开问题、记录错误或简单地终止程序。另一种选择是程序员可以“屏蔽”异常。在这种情况下,8087 会以“合理”的方式继续操作。例如,溢出的值会被设为无穷大,无效值则被设为特殊值“非数”(NaN)。对于精度异常(例如 1/3),数值会被舍入。8087 的设计者在屏蔽异常后如何以最佳方式继续运行方面投入了大量精力;手册中有数页的细节描述了所有特殊情况。⁵(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:exceptions)
异常条件的处理由微码和硬件分工完成。例如,如果 `FXCH` 微码检测到空寄存器,它会执行 `set invalid exception` 微指令。这条微指令设置一个锁存器,指示无效异常。8087 的控制寄存器包含六个屏蔽位,每种异常类型一个,用于阻止该类异常的中断。硬件将异常触发器信号与控制寄存器中的屏蔽位以及状态寄存器中的异常标志相结合,以判断是否有新的、未屏蔽的中断被触发。如果有,8087 电路会向 8086 处理器发送一个中断。
另一方面,如果中断被屏蔽,微码继续执行。对于 `FXCH`,微码会将空寄存器替换为“非数”值。最后,微码例程以 RNI(运行下一条指令)结束。这会触发许多硬件活动,但与此相关的是将异常触发器的状态复制到状态寄存器中。这样,如果程序员想要检查,异常位就会被设置。当下一个 8087 指令开始时,异常触发器被清除。由于硬件负责管理触发器、状态寄存器、控制寄存器和中断线,微码可以更简单、更小巧。
## 提取微码
8087 的微码 ROM c(似乎原文被截断?输入结束于"微码 ROM c",但后面应该是完整内容。不过根据任务,我们只需翻译给出的内容。原文最后一句不完整,我们按照原文翻译即可。)# Intel 8087 浮点芯片内部的微码:寄存器交换
来源:https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html
1980 年,Intel 推出了 8087 浮点芯片,这是一款协处理器,能让浮点运算速度提升 100 倍。该芯片影响深远,如今大多数处理器都采用 8087 引入的浮点标准。
8087 使用复杂的算法来精确计算平方根、正切和指数等函数。这些算法在芯片内部通过名为微码的低层代码实现。我是 Opcode Collective 小组的一员,正在逆向分析这些微码。在本文中,我将深入剖析 8087 指令之一——`FXCH` 的微码,并解释其工作原理。`FXCH`(浮点交换)指令用于交换两个浮点寄存器。你可能认为这条指令微不足道,但实际情况比想象的要复杂:微码用了 14 条微指令来实现这次交换操作。
Intel 8087 芯片封装在 40 引脚 DIP(双列直插式)中。(https://static.righto.com/images/8087-fxch/8087-package.jpg)
Intel 8087 芯片封装在 40 引脚 DIP(双列直插式)中。
为了探索微码,我打开了一片 8087 芯片,并用显微镜生成了高分辨率图像。巨大的微码 ROM 位于中央位置,其中保存着控制芯片的微指令。左侧的微码引擎负责逐条执行微码,处理跳转和子程序调用。芯片下半部分是“数据路径”,即执行浮点运算的电路;它被分为 16 位的数据路径(用于处理数字的指数)和 64 位的数据路径(用于处理数字的小数部分,也称为有效数字)。
Intel 8087 浮点单元芯片裸片,主要功能模块已标注。裸片尺寸为 5mm×6mm。点击查看大图。(https://static.righto.com/images/8087-fxch/8087-die-labeled.jpg)
Intel 8087 浮点单元芯片裸片,主要功能模块已标注。裸片尺寸为 5mm×6mm。点击查看大图。
本文重点关注以红色高亮显示的临时寄存器和栈寄存器。芯片有两个临时寄存器和八个栈寄存器,每个寄存器都保存着一个数字的指数和小数部分。每个寄存器还有两个标签位,用于标记该寄存器中值的类型。右侧的[栈控制电路](https://www.righto.com/2025/12/8087-stack-circuitry.html)负责管理栈,跟踪栈顶位置,以便在压栈或出栈时进行更新。
执行 8087 指令(如反正切)需要数百个内部步骤来计算结果。这些步骤通过微码实现,微指令指定算法的每个步骤。(请注意指令的两个层次:程序员使用的汇编语言指令和芯片内部未公开的低层微指令。)微码 ROM 包含 1648 条微指令,实现了 8087 的指令集。每条微指令长 16 位,执行诸如在芯片内部移动数据、两个值相加或[移位](https://www.righto.com/2020/05/die-analysis-of-8087-math-coprocessors.html)等简单操作。我正在与 Opcode Collective 合作,逆向分析这些微指令并全面理解微码(链接(https://github.com/a-mcego/granite/blob/main/tools/8087mc/bin/8087.md))。
8087 的微指令相当复杂,涉及许多边界情况和专用功能,但我会提供一个简化的概述。每条微指令由 16 位组成,如下所示。前三位指定微指令的类型,这决定了其余位的含义。第一种类型表示传输操作,即将数据从一个内部寄存器传输到另一个。两个字段分别指定源和目标。未指定的三位用于各种特殊情形。接下来是移位操作,利用桶形移位器将值左移或右移。第三种类型的微指令使用加法器/减法器,也可用于乘法或除法的循环中。第四种是各种算术控制微指令,用于配置加法器、设置舍入模式等。远跳转和远调用微指令用于跳转到或调用固定列表中的目标微地址。条件字段允许基于多种[条件](https://www.righto.com/2025/12/8087-microcode-conditions.html)进行条件跳转/调用,最后一位用于反转条件。本地跳转则允许条件跳转到附近的微指令。最后,杂项微指令包括从子程序返回、引发异常或结束微码执行。
8087 微指令的结构。(https://static.righto.com/images/8087-fxch/microcode-structure.jpg)
8087 微指令的结构。
## 数值在 8087 芯片内部的存储方式
8087 支持多种数据类型:各种尺寸的浮点数、整数以及二进制编码十进制数。但芯片内部所有数据都以 80 位浮点数的形式存储。一个数包含三个部分:64 位有效数字(小数部分)、15 位指数和一个符号位。芯片有两条独立的数据路径:一条用于有效数字,另一条用于指数和符号。
芯片有八个寄存器用于在计算过程中存储数字,如下方顶部图所示。然而,这些寄存器以一种不寻常的方式组织:作为栈来使用,数字被压入栈或从栈中弹出。你并非直接访问例如 3 号寄存器,而是访问栈顶起的第三个寄存器,记作 `ST(3)`;当值被压入或弹出时,`ST(3)` 会随之改变。这种基于栈的架构旨在改进指令集、简化编译器设计并使函数调用更高效,尽管实际效果并不如预期。
程序员视角下 8087 的寄存器组。来自《8086 系列数值运算增刊》。(https://static.righto.com/images/8087-fxch/register-set.jpg)
许多 8087 指令作用于栈顶。例如,平方根指令将栈顶的值替换为其平方根。但如果想对栈中间的值求平方根呢?解决方案就是 `FXCH` 指令,这也是本文的重点。该指令将栈顶的值与指定的栈位置交换,从而可以访问栈内部的值。
8087 还有一个对本文重要的特性:寄存器栈中的每个值都有一个关联的“标签”值,用于标记该值为有效、特殊、零或空。“正常”的浮点值被标记为 *valid*。如果浮点值是无穷大、非数 (NaN) 或非规格化数,则被标记为 *special*。零值被标记为 *zero*。最后,如果寄存器为空(例如,其值已从栈中弹出),则该寄存器被标记为 *empty*。8087 利用标签来优化性能并检测错误。¹(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:tags)例如,如果程序员从栈中弹出过多值,并试图读取一个标记为空的栈寄存器,8087 就会引发“无效操作”异常。
八个栈寄存器对程序员可见,但 8087 内部也使用临时寄存器。有两个临时寄存器对本文很重要:`tmpA` 和 `tmpB`。与栈寄存器一样,每个临时寄存器也是一个 80 位寄存器,外加两个标签位。
## `FXCH` 微码
在本节中,我将解释 `FXCH` 交换指令的微码工作原理。该指令将栈顶寄存器与栈中指定位置的寄存器进行交换。如果任一寄存器为空,该指令将引发“无效操作”异常,并用特殊值“非数”(NaN) 替换缺失的值。
该指令的微码如下,由 14 条微指令组成。²(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:microcode)第一条微指令是传输操作,源是栈顶值 `ST(0)`,目标是临时 A 寄存器。源指定会导致 64 位有效数字被放置到小数总线上,16 位指数和符号被放置到指数总线上,两个标签位被发送到标签电路。目标 `tmpA` 会导致总线上的值被存储到临时寄存器中。因此,微指令中的这些位就实现了所需的传输。第三条微指令类似,但使用的是栈内的寄存器 `ST(i)`,其索引由机器指令指定。
```
FXCH 入口点:
#0200 ST(0) -> tmpA 读取栈顶
#0201 nop 等待一个周期
#0202 ST(i) -> tmpB 读取指定的栈寄存器
#0203 if !(tmpA 或 tmpB 为空) jmp #0210 如果两个寄存器都存在则跳转
#0204 set invalid exception 设置无效异常
#0205 if (未屏蔽) jmp #0213 如果中断发生则结束
#0206 if !(tmpA 为空) jmp #0208 检查 tmpA 是否为空
#0207 NaN -> tmpA 如果是,则将 NaN 移到 tmpA
#0208 if !(tmpB 为空) jmp #0210 检查 tmpB 是否为空
#0209 NaN -> tmpB 如果是,则将 NaN 移到 tmpB
正常路径与错误路径在此汇合:
#0210 tmpB -> ST(0) 将 tmpB 保存到栈顶
#0211 nop 等待一个周期
#0212 tmpA -> ST(i) 将 tmpA 保存到指定的栈寄存器
#0213 RNI 例程结束:运行下一条指令
#0214 nop 未使用
#0215 nop 未使用
#0216 nop 未使用
```
接下来,位于微地址 `#0203` 的相对跳转展示了另一种类型的微指令:条件跳转。该微指令指定了一个条件,在本例中是测试任一临时寄存器是否为空。(即,硬件测试与临时寄存器关联的标签位,看是否有标签为“空”。)微指令中有一个位用于反转条件。最后,该微指令有一个偏移量 +6,得出跳转目标 `#0210`。使用相对偏移量而不是指定完整微地址的好处是偏移量只需 6 位。(有关条件如何求值的更多信息,请参阅我的文章 [Intel 8087 浮点芯片微码中的条件](https://www.righto.com/2025/12/8087-microcode-conditions.html)。)
如果任一寄存器为空,则下一条微指令会引发“invalid”异常。正如我将在下一节解释的,你可以对 8087 进行编程,使其在异常发生时产生中断,或者继续处理。下一条指令是一个条件跳转,测试异常是否“未屏蔽”,即是否产生了中断。在这种情况下,微码结束,由主 8086 处理器处理中断。
假设中断被屏蔽,微码现在会用特殊的“非数”值替换空值,首先检查 `tmpA`,然后检查 `tmpB`。源 `NaN` 会使电路将指数总线全部拉高,小数总线除顶部位外全部拉低。这个特定的位模式就表示非数。³(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:nan)
在微地址 `#0210` 处,空寄存器路径和正常路径汇合,将临时寄存器保存到栈寄存器中。这就是实际的交换操作发生的位置,因为 `tmpA` 和 `tmpB` 被写入与读取时相反的栈位置。最后,`RNI`(运行下一条指令)表示微码例程结束。这会停止微码引擎,使 8087 准备好执行下一条指令。
`nop`(空操作)微指令很有意思。每组栈读取或写入的中间都有一个 `nop`,这可能是寄存器的时序限制导致的。微码例程的末尾有三个 `nop` 指令,之后才开始下一个微码例程。这些指令看起来像是微码中的浪费空间;也许 `FXCH` 微码在开发过程中被缩短了三个字,从而造成了这个空隙。
## 异常
8087 有一个复杂的异常系统来处理各种问题。异常分为六类:无效操作、非规格化操作、除零、溢出、下溢或精度。例如,如果对负数开平方或试图对空寄存器执行操作,就会发生无效操作异常。溢出异常发生在数值太大而无法表示时,下溢异常则发生在数值太小而无法表示时。除零异常发生在除以零时。⁴(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:zero)精度异常发生在数字无法精确表示为浮点数时(这种情况极为常见)。最后,当数值太接近零而无法用完全精度表示时,会发生非规格化异常。
异常发生时会发生什么?8087 允许程序员为每种异常类型选择异常行为。第一种选项是异常触发 CPU 中断,以便软件处理问题。例如,软件可以尝试绕开问题、记录错误或简单地终止程序。另一种选择是程序员可以“屏蔽”异常。在这种情况下,8087 会以“合理”的方式继续操作。例如,溢出的值会被设为无穷大,无效值则被设为特殊值“非数”(NaN)。对于精度异常(例如 1/3),数值会被舍入。8087 的设计者在屏蔽异常后如何以最佳方式继续运行方面投入了大量精力;手册中有数页的细节描述了所有特殊情况。⁵(https://www.righto.com/2026/05/microcode-inside-intel-8087-floating.html#fn:exceptions)
异常条件的处理由微码和硬件分工完成。例如,如果 `FXCH` 微码检测到空寄存器,它会执行 `set invalid exception` 微指令。这条微指令设置一个锁存器,指示无效异常。8087 的控制寄存器包含六个屏蔽位,每种异常类型一个,用于阻止该类异常的中断。硬件将异常触发器信号与控制寄存器中的屏蔽位以及状态寄存器中的异常标志相结合,以判断是否有新的、未屏蔽的中断被触发。如果有,8087 电路会向 8086 处理器发送一个中断。
另一方面,如果中断被屏蔽,微码继续执行。对于 `FXCH`,微码会将空寄存器替换为“非数”值。最后,微码例程以 RNI(运行下一条指令)结束。这会触发许多硬件活动,但与此相关的是将异常触发器的状态复制到状态寄存器中。这样,如果程序员想要检查,异常位就会被设置。当下一个 8087 指令开始时,异常触发器被清除。由于硬件负责管理触发器、状态寄存器、控制寄存器和中断线,微码可以更简单、更小巧。
## 提取微码
8087 的微码 ROM c
相似文章
Intel 8087浮点芯片的指令解码
对Intel 8087浮点协处理器指令解码的详细逆向工程分析,解释主CPU与协处理器之间的交互、微码ROM的使用以及总线接口单元。
Intel 8087 浮点芯片微码中的条件
对 Intel 8087 浮点协处理器微码中使用的条件测试的详细研究,是逆向工程工作的一部分,旨在理解其算法。
Intel 8087浮点芯片的堆栈电路逆向工程
本文详细介绍了对Intel 8087浮点协处理器堆栈电路的逆向工程,解释了该芯片基于堆栈的寄存器架构和微码ROM如何实现快速浮点运算。
80386 微码反汇编
一篇博客文章,详细介绍了成功反汇编和分析 Intel 80386 微码的过程,揭示了215条指令入口点以及其复杂的内部架构。
386处理器寄存器的异常复杂电路
对英特尔386处理器寄存器电路的详细逆向工程分析,揭示了六种不同的定制电路和交织位存储。