为什么一块四十多年前的辅助芯片,能让浮点运算提速上百倍,还奠定了今天所有处理器的浮点标准?

1980年,英特尔推出了8087浮点协处理器。它把浮点运算速度提升了100倍,同时引入了一套浮点格式和算法规范,至今仍是现代处理器浮点单元的设计基础。这颗芯片的内部,用微码实现平方根、正切、指数等复杂函数,每一处设计都值得重新审视。

打开网易新闻 查看精彩图片

最近,一个叫Opcode Collective的团队开始对8087的微码进行逆向工程。他们打开芯片封装,在显微镜下采集了高分辨率图像,一块占据中心位置的庞大微码只读存储器暴露出来。这片ROM存有1648条微指令,就是它们控制着8087的全部指令集。每条微指令长16位,能完成数据搬移、加法、移位等基本操作,所有复杂函数最终都由这些细微动作组合而成。

打开网易新闻 查看精彩图片

在这个帖子里,我想带你看一条看似微不足道的指令——FXCH,也就是浮点寄存器交换。直觉上,交换两个寄存器的内容应该很简单,但微码却动用了14条微指令。为什么要这么多?这就要从芯片内部的寄存器结构和栈控制逻辑说起。

8087芯片有两个临时寄存器和八个栈寄存器,每个寄存器同时存放一个数的指数部分和尾数部分。指数走16位数据通路,尾数走64位数据通路。此外,每个寄存器还有两个标签位,用来标记所存数值的类型——比如是有效数、零,还是特殊值。芯片右侧的栈控制电路则负责维护栈顶位置,当数据压栈或出栈时,准确跟踪哪一个是栈顶

微码执行FXCH时,并不是粗暴地交换全部位,而是分步处理指数、尾数和标签,还要同步更新栈控制状态。因为8087的栈寄存器本质上是一个循环栈,物理位置不变,逻辑位置由栈顶指针定义。交换两个逻辑寄存器的同时,必须保证栈顶指针仍然指向正确的位置,同时标签信息不能错位。于是,微码先用几个周期把第一个寄存器的指数和尾数搬进临时寄存器,再把第二个寄存器的内容搬到第一个,最后从临时寄存器写回第二个,期间每一步还需插入调整标签和栈指针的微操作。

打开网易新闻 查看精彩图片

有意思的是,8087的微指令体系存在大量特例和临时性功能。比如有的微指令会根据标签位自动跳过某些步骤,有的则能触发条件跳转,形成循环。FXCH用到的14条微指令中,部分就嵌入了这种条件逻辑,并非直线执行。这使得一个“交换”动作,在微码层面变成了一次包含判断、搬运和同步的微型流程。

今天重看8087的内部实现,依然能感受到一种硬件资源极度受限时的精巧。当年的设计者没有把“简单指令就应该简单”当成教条,而是让每一条指令都服从栈体系、标签体系与数据通路的统一节奏。也正因如此,8087才能在5微米工艺上跑出令人吃惊的浮点性能,并把IEEE 754浮点标准的雏形推向前台。而Opcode Collective的逆向工作,正在让这些已经凝固在硅片里的设计思路重新流动起来。