← 返回信息流
AI 资讯Hacker News·4 天前

Intel 8087 浮点芯片微码:寄存器交换

原标题:Microcode inside the Intel 8087 floating-point chip: register exchange

速览

本文深入探讨了 Intel 8087 浮点数学协处理器的内部微码设计。内容聚焦于微码中实现寄存器交换的具体逻辑与机制。这一分析揭示了早期浮点运算硬件底层指令执行的核心细节。

AI 深度解读

Intel 8087 浮点协处理器微码深度解析:FXCH 指令的寄存器交换机制

背景

1980年,英特尔(Intel)推出了 8087 浮点协处理器。这款芯片将浮点运算的速度提升了高达 100 倍,对计算机架构产生了深远影响。如今,大多数处理器所使用的浮点标准正是由 8087 引入的。

8087 内部使用了复杂的算法来精确计算平方根、正切和指数等函数。这些算法并非通过传统的软件指令实现,而是以底层的“微码”(microcode)形式直接固化在芯片内部。微码是介于硬件电路和高级指令集之间的低级代码,负责控制处理器内部的具体操作步骤。

目前,Opcode Collective 组织正在对这款经典芯片进行逆向工程,旨在完全解析其微码逻辑。本文将深入探讨 8087 中 FXCH(浮点交换)指令的微码实现。尽管 FXCH 指令的功能看似简单——即交换两个浮点寄存器——但其底层实现却相当复杂,共由 14 条微指令构成。

为了研究这些微码,研究人员拆解了一颗 8087 芯片,并通过显微镜拍摄了高分辨率图像。芯片中央是占据主要面积的微码 ROM,其中存储着控制芯片运行的微指令;左侧是微码引擎,负责步进执行微码,处理跳转和子程序调用;芯片下半部分是“数据通路”(datapath),负责执行浮点计算,分为处理指数的 16 位数据通路和处理尾数(significand)的 64 位数据通路。

核心内容

8087 的微码架构

在 8087 中,执行一条高级指令(如反正切 arctan)可能需要数百个内部步骤。这些步骤由微码中的微指令逐一指定。这里存在两个层面的指令:程序员使用的汇编语言指令,以及芯片内部未文档化的底层微指令。

微码 ROM 共包含 1648 条微指令,实现了 8087 的整个指令集。每条微指令长度为 16 位,执行简单的操作,如在芯片内部移动数据、加法或移位。 Opcode Collective 正在致力于逆向工程这些微指令,以完全理解微码逻辑。

每条 16 位的微指令结构如下:

  • 前 3 位:指定微指令类型,决定剩余位的含义。
    • 传输操作:将数据从一个内部寄存器传输到另一个。
    • 移位操作:使用 barrel shifter(桶形移位器)对值进行左移或右移。
    • 加法/减法操作:使用加法器/减法器,也可用于循环中的乘法或除法。
    • 算术控制:配置加法器、设置舍入模式等。
    • 远跳转/远调用:跳转到固定列表中的目标微地址。
    • 条件跳转/调用:基于多种条件进行跳转,最后一位用于反转条件。
    • 本地跳转:对附近的微指令进行条件跳转。
    • 杂项:包括返回子程序、引发异常或结束微码执行等。

8087 内部的数据存储与寄存器结构

虽然 8087 支持多种数据类型(各种大小的浮点数、整数、BCD 码),但在内部,所有数据均以 80 位浮点数 形式存储。一个 80 位数值由三部分组成:

  1. 64 位尾数(significand,即小数部分)。
  2. 15 位指数(exponent)。
  3. 1 位符号位(sign bit)。

芯片拥有两条独立的数据通路:一条处理尾数,另一条处理指数和符号。

栈式寄存器架构

8087 拥有 8 个用于计算过程中存储数字的寄存器。与传统寄存器不同,它们被组织成一个(stack)结构。

  • 数值通过栈顶压入(push)和弹出(pop)。
  • 程序员不直接访问“寄存器 #3”,而是访问“栈顶下方的第 N 个寄存器”,记为 ST(3)。随着数值的压入和弹出,ST(3) 所指向的物理寄存器会发生变化。
  • 这种基于栈的架构旨在简化编译器设计并提高函数调用效率,尽管实际效果并未完全达到预期。
  • 许多 8087 指令仅作用于栈顶。例如,平方根指令会将栈顶的值替换为其平方根。

标签(Tag)机制

每个栈寄存器中的值都关联一个“标签”(tag),用于标识值的类型:

  • Valid(有效):正常的浮点值。
  • Special(特殊):无穷大、NaN(非数)或非规格化值。
  • Zero(零):零值。
  • Empty(空):寄存器为空(例如值已被弹出)。

标签机制用于优化性能和错误检测。如果程序员弹出过多值并尝试读取标记为“空”的寄存器,8087 会引发“无效操作”异常。

此外,芯片内部还有两个重要的临时寄存器:tmpAtmpB。它们也是 80 位寄存器,带有两个标签位,在微码执行中起关键作用。

FXCH 指令的微码实现

FXCH(Floating-point Exchange)指令用于交换栈顶寄存器与指定栈位置的寄存器中的值。这是访问栈中间值的关键机制。

执行逻辑: 如果参与交换的任一寄存器为空,指令将引发“无效操作”异常,并将缺失的值替换为特殊值 NaN。

微码流程详解(共 14 条微指令):

  1. #0200 (Transfer): 将栈顶值 ST(0) 传输到临时寄存器 tmpA
    • 源操作将 64 位尾数放到尾数总线,16 位指数和符号放到指数总线,标签位发送到标签电路。
    • 目标操作将总线上的值存入 tmpA
  2. #0201 (NOP): 等待一个时钟周期。
  3. #0202 (Transfer): 将指定位置的栈寄存器 ST(i)(索引由机器指令指定)传输到临时寄存器 tmpB
  4. #0203 (Conditional Jump): 检查 tmpAtmpB 是否为空。
    • 如果两者都不为空(即 !(tmpA or tmpB empty)),则跳转到 #0210 执行实际的交换逻辑。
  5. #0204 (Exception): 如果上述条件不满足,设置“无效操作”异常标志。
  6. #0205 (Conditional Jump): 检查异常是否被屏蔽(unmasked)。
    • 如果异常未屏蔽(即需要中断),跳转到 #0213 结束执行。
  7. #0206 (Conditional Jump): 检查 tmpA 是否为空。
  8. #0207 ...: 后续微指令继续处理异常恢复、标签更新以及最终的寄存器值交换逻辑(原文在此处截断,但根据微码逻辑,后续步骤将涉及将 tmpAtmpB 的值写回目标寄存器,并更新相应的标签位)。

关键要点

  • 微码的重要性:8087 的复杂运算(如平方根)并非由简单的硬件电路直接完成,而是通过存储在 ROM 中的 1648 条 16 位微指令序列来实现。
  • 栈式架构:8087 使用基于栈的寄存器模型(ST(0)ST(7)),而非传统的随机访问寄存器。这使得编译器设计
查看原文 →righto.com