Notes on the Pentium's Microcode Circuitry
关于奔腾(Pentium)微代码电路的笔记
计算机历史、修复老式计算机、IC逆向工程以及其他相关内容
关于奔腾(Pentium)微代码电路的笔记
大多数人认为机器指令是计算机执行的基本步骤。然而,许多处理器在底层还有另一层软件:微代码。有了微代码,控制逻辑不再是由复杂的逻辑门构建,而是由存储在微代码 ROM 中的代码(即微代码)实现。为了执行一条机器指令,计算机内部会执行几个更简单的微指令,这些微指令由微代码指定。在这篇文章中,我将研究初代奔腾(Pentium)中的微代码 ROM,观察其底层的电路。
下图显示了显微镜下奔腾(Pentium)缩略图大小的硅芯片。我已经标记了主要的功能模块。微代码 ROM 在右侧突出显示。如果仔细观察,你可以看到微代码 ROM 由两个矩形的存储体组成,一个在另一个之上。
这张奔腾(Pentium)芯片的照片显示了微代码 ROM 的位置。点击此图片(或任何其他图片)可查看更大的版本。
下图显示了两个微代码 ROM 存储体的特写。每个存储体提供 45 位的输出;它们共同实现了一个 90 位长的微指令。每个存储体由排列成 288 行和 720 列的晶体管网格组成。微代码 ROM 保存了 4608 条微指令,总共 414720 位。在这个放大倍数下,ROM 看起来平淡无奇,但它被水平导线覆盖,每条导线只有 1.5 微米厚。
来自 ROM 的 90 条输出线,以及六条线离开 ROM 的特写。
如上图所示,ROM 的 90 条输出线被收集到存储体之间的一束导线中。细节显示了六位如何从存储体中出来并加入该束导线。这束导线从 ROM 的左侧出来,传输到芯片的各个部分,并控制芯片的电路。输出线位于芯片的顶层金属层 (M3) 中:奔腾(Pentium)有三层金属布线,M1 在底部,M2 在中间,M3 在顶部。
奔腾(Pentium)的微指令中有大量的位,90 位,而 8086 中只有 21 位。据推测,奔腾(Pentium)具有“水平”微代码架构,其中微代码位对应于低级控制信号,而不是“垂直”微代码,其中位被编码为更密集的微指令。我没有任何关于奔腾(Pentium)微代码编码的信息;与 8086 不同,奔腾(Pentium)的专利没有提供任何线索。8086 的微代码 ROM 保存了 512 条微指令,远少于奔腾(Pentium)的 4608 条微指令。考虑到奔腾(Pentium)指令集的复杂性要大得多,包括芯片上的浮点单元,这很有道理。
下图显示了奔腾(Pentium)微代码 ROM 的特写。对于这张图片,我移除了三层金属层和多晶硅层,以暴露芯片的底层硅。可以看到硅掺杂的图案,显示了晶体管,从而显示了存储在 ROM 中的数据。如果你有足够的时间,你可以通过检查硅并查看晶体管的位置来从 ROM 中提取位。
ROM 的特写,显示了位是如何在晶体管的布局中编码的。
在解释 ROM 的电路之前,我将回顾一下 NMOS 晶体管是如何构建的。晶体管可以被认为是源极和漏极之间的开关,由栅极控制。源极和漏极区域(绿色)由掺杂有杂质的硅组成,以改变其半导体特性,形成 N+ 硅。(这些区域在上图中可见。)栅极由一层多晶硅(红色)组成,多晶硅通过非常薄的绝缘氧化物层与硅隔离。每当多晶硅穿过有源硅时,就会形成晶体管。
显示 NMOS 晶体管结构的示意图。
位通过网格中晶体管的模式存储在 ROM 中。晶体管的存在与否存储了 0 或 1 位。1 下面的特写显示了微代码 ROM 的八位。存在四个晶体管,并且存在四个晶体管缺失的间隙。因此,ROM 的这一部分保存了四个 0 位和四个 1 位。对于下面的图,我移除了三个金属层和多晶硅,以显示底层的硅。我用绿色标记了掺杂(有源)硅区域,并用红色绘制了水平多晶硅线。如上所述,如果多晶硅穿过掺杂硅,则会创建一个晶体管。因此,ROM 的内容由硅区域的模式定义,该模式创建了晶体管。
微代码 ROM 的八位,存在四个晶体管。
水平硅线用作布线,以向晶体管提供接地,而水平多晶硅线选择 ROM 中的一行。该行中的晶体管将导通,将相关的输出线拉低。也就是说,一行中晶体管的存在会导致输出被拉低,而晶体管的缺失会导致输出线保持高电平。
与上面八位对应的原理图。
下图显示了硅、多晶硅和底部金属 (M1) 层。我从左侧移除了金属,以显示下面的硅和多晶硅,但垂直金属线的模式在那里继续存在。如前所示,硅模式形成晶体管。每条水平金属线都通过一条金属线(未显示)连接到地。水平多晶硅线选择一行。当多晶硅线穿过掺杂硅时,会形成晶体管的栅极。两个晶体管可以共享漏极,如左侧的晶体管对中所示。
显示硅、多晶硅和 M1 层的示意图。
垂直金属线形成输出。圆圈是金属线和晶体管的硅之间的触点。2 短金属跳线将多晶硅线连接到上面的金属层,这将在接下来进行描述。
下图显示了 ROM 的左上角。淡黄色的金属线是顶层金属层 (M3),而微红色的金属线是中间金属层 (M2)。粗淡黄色的 M3 线将接地分配到 ROM。在水平 M3 线下方,水平 M2 线也分配接地。黑色点的网格是 M3 线和 M2 线之间的许多触点,提供了低电阻连接。M2 线又连接到下面的垂直 M1 接地线——这些宽垂直线隐约可见。这些 M1 线连接到硅,如前所示,为每个晶体管提供接地。这说明了奔腾(Pentium)中电源分配的复杂性:粗顶层金属 (M3) 是 +5 伏和接地通过芯片的主要分配方式,但电源必须通过 M2 和 M1 向下传递才能到达晶体管。
ROM 的左上角。
上面另一个重要的特征是水平金属线,它有助于分配行选择信号。如前所示,水平多晶硅线为晶体管提供行选择信号。但是,多晶硅不如金属导电,因此长多晶硅线的电阻太大。解决方案是并行运行金属线,定期连接到底层的多晶硅线,从而降低总电阻。由于垂直金属输出线位于 M1 层中,因此水平行选择线在 M2 层中运行,这样它们就不会发生冲突。M1 层中的短“跳线”将 M2 线连接到多晶硅线。
总而言之,每个 ROM 存储体都包含一个晶体管和晶体管空位的网格,以定义 ROM 的位。ROM 经过精心设计,因此不同的层——硅、多晶硅、M1 和 M2——协同工作,以最大限度地提高 ROM 的性能和密度。
微代码地址寄存器
当奔腾(Pentium)执行一条指令时,它会将每条微指令的地址提供给微代码 ROM。奔腾(Pentium)将此地址(微地址)保存在微代码地址寄存器 (MAR) 中。MAR 是一个 13 位寄存器,位于微代码 ROM 的上方。
下图显示了位于上 ROM 存储体上方的微代码地址寄存器。它由 13 位组成;每一位都有多个锁存器,用于保存值以及任何推送的子程序微地址。在位 7 和位 8 之间,一些缓冲电路会放大发送到每一位电路的控制信号。在右侧,驱动器会放大 MAR 的输出,将信号发送到我将在下面讨论的行驱动器和列选择电路。MAR 的左侧是一个 32 位寄存器,它显然与微代码 ROM 无关,尽管我尚未确定其功能。
微代码地址寄存器位于上 ROM 存储体的上方。
来自微代码地址寄存器的输出选择微代码 ROM 中的行和列,我将在下面解释。MAR 的位 12 到位 7 选择 8 行的块,而位 6 到位 4 选择此块中的一行。位 3 到位 0 从每组 16 列中选择一列,以选择一个输出位。因此,微代码地址控制 ROM 提供的字。
可以对微代码地址寄存器执行几种不同的操作。在执行机器指令时,必须将 MAR 加载到相应微代码例程的地址。(我尚未确定如何生成此地址。)当执行微代码时,MAR 通常会递增以移动到下一条微指令。但是,MAR 可以根据需要分支到新的微地址。MAR 还支持微代码子程序调用;它将推送当前微地址并跳转到新的微地址。在微子程序的末尾,微地址会被弹出,因此执行会返回到先前的位置。MAR 支持三级子程序调用,因为它包含三个寄存器来保存推送的微地址的堆栈。
MAR 接收来自位于 MAR 上方的标准单元逻辑的控制信号和地址。奇怪的是,在 Intel 发布的奔腾(Pentium)的布局图中,此标准单元逻辑被标记为分支预测逻辑的一部分,该逻辑位于其上方。但是,仔细跟踪来自标准单元逻辑的信号表明它连接到微代码地址寄存器,而不是分支预测器。
行选择驱动器
如上所述,每个 ROM 存储体都有 288 行晶体管,带有用于选择其中一行的多晶硅线。ROM 的右侧是基于微地址激活其中一条行选择线的电路。每一行都匹配一个不同的 9 位地址。一种直接的实现方式是为每一行使用一个 9 输入 AND 门,以匹配 9 个地址位或其补码的特定模式。
但是,这种实现方式需要 576 个非常大的 AND 门,因此它是不切实际的。相反,奔腾(Pentium)使用了一种优化的实现方式,每个 8 行组使用一个 6 输入 AND 门。其余三个地址位在 ROM 的顶部解码一次。因此,每一行只需要一个门,检测到是否选择了它的八行组,以及是否选择了八行中的特定一行。
行驱动器电路的简化原理图。
上面的原理图显示了一组八行的电路,略有简化。3 在顶部,对三个地址位进行解码,生成八条输出线,一次激活一条。其余六个地址位被反转,为解码电路提供位及其补码。因此,9 位被转换为 20 个信号,这些信号流过解码器,大量的导线,但并非无法管理。每组八行都有一个 6 输入 AND 门,该门匹配一个特定的 6 位地址,该地址由哪些输入被补充以及哪些输入未被补充决定。4 左侧的 NAND 门和反相器结合了 3 位解码和 6 位解码,从而激活了适当的行。
由于每一行最多有 720 个晶体管,因此需要用高电流驱动行选择线。因此,行选择驱动器使用大型晶体管,大约是普通晶体管的 25 倍。为了将这些晶体管安装到与其余解码电路相同的垂直间距中,使用了一种巧妙的封装。每组 8 行的驱动器被封装到 3×3 网格中,除了第一列有两个驱动器(因为该组中有 8 个驱动器,而不是 9 个)。为了避免间隙,第一列中的驱动器在垂直方向上更大,在水平方向上被压缩。
输出电路
下面的原理图显示了多路复用器电路,该电路为微代码输出位选择 16 列中的一列。第一级有四个 4 对 1 多路复用器。接下来,另一个 4 对 1 多路复用器选择一个输出。最后,一个 BiCMOS 驱动器放大输出,以传输到处理器的其余部分。
16 对 1 多路复用器/输出驱动器。
更详细地说,ROM 和第一个多路复用器本质上是 NMOS 电路,而不是 CMOS。具体来说,ROM 的晶体管网格由 NMOS 晶体管构成,这些晶体管可以将列线拉低,但网格中没有 PMOS 晶体管可以将线拉高(因为这会使 ROM 的尺寸加倍)。相反,多路复用器包括预充电晶体管,以将线拉高,大概是在读取 ROM 之前的时钟相位中。线的电容将使线保持高电平,除非它被网格中的晶体管拉低。激活多路复用器中的四个晶体管之一(通过控制信号“a”、“b”、“c”或“d”)以选择所需的线。输出进入一个“保持器”电路,该电路使输出保持高电平,除非它被拉低。保持器使用一个反相器,该反相器带有一个只能提供小拉升电流的弱 PMOS 晶体管。更强的低电平输入将克服此晶体管,从而切换保持器的状态。
此多路复用器的输出以及其他三个多路复用器的输出进入第二级多路复用器,5 该多路复用器根据控制信号“e”、“f”、“g”和“h”选择其四个输入之一。此多路复用器的输出保存在由两个反相器构建的锁存器中。第二个锁存器具有弱晶体管,因此可以轻松地将锁存器强制设置为所需状态。来自第一个锁存器的输出通过 CMOS 开关进入第二个锁存器,从而创建一个触发器。
来自第二个锁存器的输出进入一个 BiCMOS 驱动器,该驱动器驱动 90 条微代码输出线之一。大多数处理器由 CMOS 电路(即 NMOS 和 PMOS 晶体管)构建,但奔腾(Pentium)由 BiCMOS 电路构建:双极晶体管以及 CMOS。当时,双极晶体管提高了高电流驱动器的性能;请参阅我关于 奔腾(Pentium)的 BiCMOS 电路 的文章。
下图显示了微代码输出的三位。此电路适用于上 ROM 存储体;该电路对于下存储体是镜像的。该电路与上面的原理图匹配。三个块中的每一个都有来自 ROM 网格的 16 条输入线。四个 4 对 1 多路复用器将其减少到 4 条线,第二个多路复用器选择一条线。结果被锁存并通过输出驱动器放大。(请注意双极晶体管的大正方形形状。)接下来是移位寄存器,该移位寄存器处理用于测试的微代码 ROM 输出。移位寄存器使用 XOR 逻辑进行反馈;与电路的其余部分不同,XOR 逻辑是不规则的,因为只有一些位被馈送到 XOR 门中。
微代码的三个输出位,我移除了三个金属层以显示多晶硅和硅。
用于测试的电路
为什么微代码 ROM 有移位寄存器和 XOR 门?原因是像奔腾(Pentium)这样的芯片很难测试:如果 310 万个晶体管中的一个坏了,你如何检测到它?对于像 8086 这样的简单处理器,你可以运行指令集,并且相当确信任何问题都会出现。但是对于复杂的芯片,几乎不可能设计出可以测试微代码 ROM 的每一位、缓存的每一位等的指令序列。从 386 开始,Intel 向处理器添加了电路,专门用于简化测试;386 中大约 2.7% 的晶体管用于测试。
奔腾(Pentium)具有用于许多 ROM 和 PLA 的这种测试电路,包括导致臭名昭著的 FDIV 错误 的除法 PLA。为了测试处理器内部的 ROM,Intel 添加了电路来扫描整个 ROM 并校验其内容。具体来说,伪随机数生成器运行每个地址,而另一个电路计算 ROM 输出的校验和,形成一个“签名”字。最后,如果签名字具有正确的值,则 ROM 几乎肯定是正确的。但是,即使存在单个位错误,校验和也会错误,并且该芯片将被拒绝。
伪随机数和校验和都使用线性反馈移位寄存器 (LFSR) 实现,线性反馈移位寄存器是一个移位寄存器,带有一些 XOR 门,用于将输出反馈到输入。有关 386 中测试电路的更多信息,请参阅由 Pat Gelsinger 撰写的 80386 的设计和测试,Pat Gelsinger 多年后成为 Intel 的 CEO。
结论
你可能会认为实现 ROM 很简单,但是奔腾(Pentium)的微代码 ROM 由于其优化的结构及其用于测试的电路而异常复杂。我无法确定有关微代码工作原理的太多信息,除了微指令是 90 位宽,并且 ROM 总共保存了 4608 条微指令。但是希望你发现这次对电路的观察很有趣。
免责声明:所有这些都应被视为略带推测性,并且可能存在一些错误。我不想在每个语句前面加上“我认为……”,但你应该假装它在那里。我计划写更多关于奔腾(Pentium)的实现的文章,所以请在 Bluesky (@righto.com) 或 RSS 上关注我以获取更新。Peter Bosch 已经对 Pentium II 微代码进行了一些逆向工程;他的信息在这里。
脚注和参考文献
- 晶体管对应于 0 位还是 1 位是任意的。晶体管会将输出线拉低(即 0 位),但信号可以在使用前反转。更多对电路或 ROM 内容的分析将消除这一点。↩
- 当查看像这样的 ROM 时,触点模式似乎应该告诉你 ROM 的内容。不幸的是,这行不通。由于触点可以连接到一个或两个晶体管,因此触点模式无法为你提供足够的信息。你需要查看硅以确定晶体管模式,从而确定位。↩
- 我简化了行驱动器原理图。最有趣的区别是 NAND 门经过优化,每个使用三个晶体管,而不是四个晶体管。诀窍是,一个 NMOS 晶体管基本上在 8 个驱动器组中共享;一个反相器驱动所有八个门的低端。第二个简化是 6 输入 AND 门由两个 3 输入 NAND 门和一个 NOR 门出于电气原因而实现。 另外,将 3 位转换为 8 条选择线的解码器位于存储体之间,在右侧,而不是像我在原理图中显示的那样位于 ROM 的顶部。同样,6 个行选择位的反相器也不在顶部。相反,在 ROM 的右侧有一列排列的 6 个反相器和 6 个缓冲器,这对于布局而言效果更好。这些是 BiCMOS 驱动器,因此它们可以提供长导线和它们必须驱动的许多晶体管栅极所需的高电流输出。↩
- 6 输入 AND 门的输入以二进制计数模式排列,按顺序选择每一行。这种二进制排列是 ROM 的解码器电路的标准配置,并且是识别芯片上 ROM 的好方法。奔腾(Pentium)有 36 个行解码器,而不是你期望的来自 6 位输入的 64 个。ROM 被制成所需的尺寸,而不是完全是 2 的幂。在大多数 ROM 中,很难确定 ROM 是从下到上寻址还是从上到下寻址。但是,由于微代码 ROM 的计数模式被截断,因此可以看出顶部存储体从顶部的 0 开始并向下计数,而底部存储体则相反,从底部的 0 开始并向上计数。↩
- 对于任何尝试读取 ROM 内容的人的注释:一组 16 个条目的顺序似乎不一致,因此直接尝试视觉读取 ROM 将最终得到打乱的数据。也就是说,某些组已反转。我没有看到哪些组已反转的任何明显模式。
第一级输出多路复用器的特写。此图显示了 M1 金属层。 在上图中,查看来自选择线的触点,将选择线连接到多路复用晶体管。左侧的触点是右侧触点的镜像,因此将以相反的顺序访问这些列。但是,这种镜像模式并不一致;有时相邻的组是镜像的,有时则不是。 我不知道为什么电路具有这种布局。有时镜像相邻的组会使布局更有效,但是不一致的镜像反对这一点。也许自动布局系统决定这是最好的方法。或者,也许 Intel 这样做是为了对逆向工程进行一些混淆。↩