Hotdry.
compilers

从硅晶到逻辑:Intel 8086 处理器 ALU 微架构逆向解析

通过芯片die照片逆向工程,深入剖析 Intel 8086 处理器的算术逻辑单元实现细节,揭示曼彻斯特进位链、可配置多路复用器与动态锁存器的精妙设计。

Intel 8086 处理器于 1978 年问世,凭借其 16 位架构与 x86 指令集奠定了现代计算的发展轨迹。这款芯片虽已诞生近半个世纪,但其内部电路的精妙设计仍值得深入探究。通过对芯片硅晶的显微照片进行逆向工程,我们可以还原出 ALU 的具体实现细节,理解 1970 年代末的处理器设计者们如何在有限的晶体管资源下实现高效能的算术逻辑运算。

ALU 在芯片中的布局与整体架构

8086 处理器 die 的显微照片清晰地展示了各功能模块的分布。ALU 位于芯片的左下角,占据了相当大的 die 面积。芯片上部是通用寄存器和专用寄存器组,左上角有一个独立的地址加法器用于段寄存器与偏移量的计算,这一设计将内存地址计算与算术运算分离,提升了整体执行效率。右下角则是微代码 ROM,存储着各指令的执行微程序。

ALU 本身采用 16 位并行结构,由 16 个几乎完全相同的位级电路级联而成。上部 8 级负责处理低字节(位 7 至 0),下部 8 级处理高字节(位 15 至 8)。两级之间是标志位寄存器,负责记录运算结果的状态信息,包括零标志、进位标志、溢出标志、奇偶标志等,这些标志位是条件跳转指令的依据。值得注意的是,标志位电路的设计相当复杂,每个标志位都有其独特的实现逻辑和处理边界情况的专用电路,甚至包含一个未公开的零寄存器供微代码使用。

曼彻斯特进位链与并行进位优化

ALU 的核心功能是执行加法和减法运算,而进位信号的处理直接决定了运算速度。全加器是构建多位加法器的基本单元,每个全加器接收两个输入位和一个进位输入,输出本位求和结果和进位输出。若简单地将 16 个全加器串联,进位信号需要逐级传播,导致严重的延迟问题。

8086 采用了曼彻斯特进位链技术来解决这一问题,这一技术最早可追溯至 1959 年的超级计算机项目。其核心思想是在每个位级并行计算三个关键信号:进位生成(carry-generate)、进位传播(carry-propagate)和进位阻塞。当两个输入位均为 1 时,无论进位输入为何,都必然产生进位输出,这称为进位生成。当两个输入位分别为 0 和 1 时,进位输出完全取决于进位输入,这称为进位传播。当两个输入位均为 0 时,无论进位输入为何,都不会产生进位输出。

在曼彻斯特进位链中,进位传播信号控制一个晶体管的开关状态。当进位传播为真时,晶体管导通,进位信号得以从当前级传递到下一级。当进位传播为假时,晶体管关闭,当前级根据进位生成信号决定是否产生本地进位。由于所有位级的传播和生成信号可以同时计算,进位只需沿链式结构流动,避免了逐级逻辑运算的累积延迟。这一设计使 8086 的 16 位加法运算能够在有限的时钟周期内完成。

可配置多路复用器实现通用逻辑功能

8086 ALU 不仅能执行加法,还需要支持与(AND)、或(OR)、异或(XOR)等逻辑运算以及移位操作。传统设计会为每种运算配置独立的逻辑电路,但这会显著增加芯片面积和功耗。8086 采用了一种更加巧妙的方案:使用可配置的多路复用器来实现任意两输入布尔函数。

任意两输入布尔函数的真值表包含四个输出值,分别对应四种输入组合(00、01、10、11)。如果向一个四选一多路复用器输入这四个值,并以两个输入位作为选择信号,则多路复用器的输出就是该布尔函数的计算结果。例如,AND 函数的真值表为 0、0、0、1,将这些值输入多路复用器即可实现与运算。类似地,将 0、1、1、0 输入多路复用器则实现异或运算。通过为多路复用器配置不同的真值表,相同的硬件电路可以执行任意逻辑运算。

在 8086 ALU 中,多路复用器被用来实现进位生成和进位传播信号的形成逻辑。这种设计将 ALU 转变为真正的通用算术逻辑单元,只需改变多路复用器的配置数据,即可切换不同的运算模式。与为每种运算设计专用电路相比,这种可配置方案大幅减少了晶体管数量,同时保持了运算的灵活性。多路复用器采用传输晶体管实现,相比标准逻辑门构成的 multiplexer,这种方式更加紧凑节能,是早期处理器设计的常见优化手段。

左移操作的进位链复用技巧

移位操作是 ALU 的另一项重要功能。8086 的左移一位操作利用进位链实现了极为简洁的硬件实现。在这一设计中,第一个操作数的当前位被直接送到进位输出位置,进位信号随后通过异或门传递至求和输出端,从而实现整体左移一位的效果。

具体来说,当执行左移时,进位传播信号被强制设为 0。这产生两个效果:首先,它使第一个操作数的当前位直接传递到进位输出;其次,它将异或门转变为直通门,使进位输入直接传递到求和输出。由于进位输出实际上就是左移后的新本位,而进位输入则是右邻位传来的旧本位,整个操作序列实现了左移一位的效果。这种复用进位链的设计避免了为移位操作单独设计电路,体现了硬件设计中的资源复用思想。右移操作则有独立的实现电路,未集成在这一通用结构中。

NMOS 工艺下的电路实现

8086 采用 NMOS 工艺制造,这是 1970 年代集成电路的主流技术。芯片以掺杂硅为基底,通过扩散砷或硼形成导电区域和晶体管结构。 polysilicon(多晶硅)层位于硅基底之上,用于形成晶体管的栅极以及各组件之间的连线。最上层的金属层则提供额外的布线和电源分配网络。与现代 CMOS 工艺相比,NMOS 工艺只有 N 型晶体管,没有对应的 P 型晶体管,因此实现某些逻辑功能需要使用上拉电阻而非互补结构。

反相器是最基本的逻辑单元,在 NMOS 工艺中由一个晶体管和一个上拉电阻构成。当输入为低电平时,晶体管截止,上拉电阻将输出拉高;当输入为高电平时,晶体管导通,将输出拉低,从而实现逻辑非功能。更复杂的逻辑门如或非门(NOR)可以通过串联晶体管实现。两个输入端的或非门在任一输入为高电平时,对应的晶体管导通,将输出拉低;只有当所有输入都为低电平时,输出才被上拉电阻拉高。die 照片显示,这些逻辑门在硅晶上的布局经过精心优化以节省空间,晶体管的形状并非简单的矩形,而是根据周围电路的走线需求进行了不规则调整。

临时寄存器组是 ALU 的数据输入来源,包括 A、B、C 三个 16 位寄存器。这些寄存器对程序员不可见,仅供内部微架构使用。任何寄存器都可以向 ALU 提供第一个操作数,但第二个操作数始终来自 B 寄存器。寄存器通过双向 ALU 总线与 ALU 连接,可同时支持读写操作。尽管这看似会成为性能瓶颈(需要两个时钟周期加载寄存器再加一个时钟周期获取结果),但这一设计在当时已被证明足够高效。寄存器采用动态锁存器实现,利用线缆和晶体管的电容效应存储数据,相比静态锁存器更加紧凑,仅需两个晶体管和两个反相器即可实现一位存储。

硬件实现的边界与微代码补充

8086 ALU 的设计虽然精巧,但并未包含乘法、除法和多位移位的专用硬件。这些操作通过微代码实现,利用 ALU 的基本运算能力组合完成。例如,16 位乘法通过重复执行加法和左移操作逐步累加部分积;除法则通过重复减法和右移实现;多位移位通过多次单位移位操作拼接。

这种硬件与微代码的分工策略在早期处理器中非常普遍。硬件实现高频基本运算以保证性能,微代码处理低频复杂操作以节省芯片面积。8086 的微代码 ROM 位于 die 的右下角,存储着各指令对应的微操作序列。每条复杂指令的执行都需要微代码 ROM 中的多个微指令协同完成,这种分层设计使处理器能够在有限的硬件资源下支持丰富的指令集。

通过对 8086 芯片 die 的逆向工程,我们得以一窥 1970 年代末处理器设计的工程智慧。曼彻斯特进位链实现了高速并行进位传播,可配置多路复用器将 ALU 转变为通用函数生成器,动态锁存器在节省面积的同时保证了数据存储的可靠性。这些设计思想在更现代的处理器中依然以不同的形式延续着,体现了硬件工程中经得起时间检验的设计原则。

资料来源:Ken Shirriff 对 Intel 8086 处理器 ALU 的逆向工程分析(righto.com)。

查看归档